locklog

module
v0.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 14, 2026 License: Apache-2.0

README

CI Latest release Go version

Let any AI agent investigate your logs: counts, patterns and traces come back
with emails, IPs and secrets masked, and a value in clear waits for you.

An agent (here Claude Code, left) and lox run (right, outside the agent): free calls come back masked, an unmask waits for you.

Quick start · How it works · Docs · Lock Family · locklog.dev


locklog is a Lock of the Lock Family, harness security for AI agents. A console held by a human reads your logs; the agent asks over MCP and gets masked, bounded, typed answers: counts, patterns, traces, lines around a hit.

[!NOTE] Pre-release (v0.3.x). The console is started by lox run only, from lockhub v0.10.0. See the install status.

Why locklog

  • Masked before the model. Emails, IPs, card numbers, national ids and the other values locklog detects become pseudonyms (⟦email:7F3KQ2M9ZD4X⟧); secrets become ⟦secret⟧.
  • The agent never holds the logs. It never reads files, the Docker socket or a backend's credentials: the console does, in its own account and container.
  • Approval outside the agent. Reads within budgets are free. A scan beyond a budget or a value in clear is a ticket that waits for you in lox run, and unmask is off by default on production.
  • Read-only. No write path to any log or backend, and every call is audited without clear values.

Install

brew trust davidgodefroid/tap
brew install davidgodefroid/tap/lockfamily

That installs the Lock Family, locklog included. For locklog alone: brew install davidgodefroid/tap/locklog (with lox for lox add locklog and lox run), or the signed install script, which installs the launcher:

curl -fsSL https://locklog.dev/install.sh | sh

A Linux host with the logs, Docker ≥ 19.03 and cosign. Status, the script read first, and production placement: docs/install.md.

Quick start

On a non-production profile first (a host agent runs on your own account, where it could still read the logs directly):

  1. In your project, add the lock. lox add builds a profile from the logs this host has (never a secret), wires your agent and checks the setup:

    cd ~/projects/shop
    lox add locklog
    
  2. In a terminal of its own, outside any agent, keep lox run open. It starts the console, and every ticket shows up there:

    lox run
    
  3. Start your agent in the project (claude, codex, gemini, …) and ask: "when did the 502s start?"

lox add wires Claude Code; for Codex, Cursor or Gemini CLI, also run locklog init codex (or cursor, gemini). On production, run the agent in lea or in its own container (docs/setup.md).

Highlights

🕶️ Masked by construction
Every record is masked before any predicate runs. A clear email in a query is refused; equality on a pseudonym still finds one user's records.

🔎 Investigation tools, not a query language
locklog_count, locklog_patterns, locklog_trace, locklog_context, locklog_search, locklog_tail. Text never goes to a backend.

⚖️ Free within budgets, approved beyond
Reads are bounded per call and per hour. locklog_scan asks you once for its whole plan.

📚 Your sources
Files (rotation, gzip, zstd), journald, Docker container logs and Loki; Elasticsearch and OpenSearch as a preview.

More: the highlights in full and a comparison.

How it works

 host (you)
   lox run (lockhub): the hub and the decisions, in a terminal of its own
     └─ console container   uid 10051, no capability, read-only root,
          read-only binds of the approved log directories,
          pseudonym keys, index and audit in its own volume
 agent (lea, your own container, or the host for the trial)
   MCP server `locklog mcp` → the console's socket (peer uid checked by the kernel)
  1. The console reads the approved sources, and only those.
  2. Each call gets a byte plan from the time range and trusted selectors only; admission and stopping points never depend on what matched.
  3. Every record is masked first; then the agent's predicates run on the masked view.
  4. The answer leaves capped, as JSON under an "untrusted content" header.

Reads within budgets are free and audited. A scan beyond a budget, an unmask or an approved lookup is a ticket at lox run; a profile's auto rules (auto, ask, deny) decide which lox run may approve alone, and the default asks you. The full layout, the decision table, the sources and the masking benchmark: docs/architecture.md.

Safety model

  • The console is the enforcement point. It alone reads logs, holds credentials and pseudonym keys, and decides what leaves.
  • OS separation. Only the clients group, the image's agent and the uids you list reach the socket, never root; no Docker socket in any locklog container.
  • Approvals bound to the plan. Single use; an unmask re-reads the record and is refused if anything moved. Secrets are never unmasked.
  • Preconditions. The agent must not reach the logs another way (P1), agents of one uid are one trust domain (P2), and only the console holds backend read credentials (P3). locklog doctor checks the usual ways P1 fails.
  • Known limits. locklog masks what it detects: person names (unless opted in), usernames in free text, postal addresses, private IPs and business ids are not. Pseudonymised data is still personal data under the GDPR.

Threat model, invariants, what is not masked and retention: docs/security-model.md. A company bounds every profile of a machine with the Lock Family's managed configuration (locklog's keys).

Documentation

Doc What it covers
docs/install.md status, Homebrew, install.sh, the host-agent trial, production placement
docs/setup.md the launcher verbs: profile add, init <agent>, doctor, the own-container recipe
docs/usage.md the profile file, the managed configuration, the agent's tools, budgets, lox run and its auto rules, the console, tickets
docs/architecture.md process layout, the life of a call, who decides what, sources, masking benchmark
docs/security-model.md what locklog protects and enforces, preconditions, masking pipeline, what is not masked, retention
docs/sources.md journald, Docker and Podman: what the spikes measured
docs/loki.md Loki 3's detected_level, a test Loki with past data
docs/performance.md backend and masking throughput, and the defaults derived
docs/recipes/holmesgpt.md HolmesGPT with locklog, in its own container
CHANGELOG.md what changed, release by release

The site, locklog.dev, is built from site/. The demo is generated by python3 scripts/brand/demo.py > site/assets/demo.svg.

The Lock Family

Repo What it does
lockfamily The family site (lockfamily.dev) and the one-line installer.
locksql SQL databases: the agent queries, PII comes back masked; connections and writes wait for you.
lockmq RabbitMQ: masked queue inspection; connections, peeks and unmasked reads wait for you.
lockfile Files (S3, SFTP, disk): the agent asks yes/no questions about files it never reads.
lockhttp Outbound HTTP(S): reads of trusted hosts pass; anything that sends data or reaches an unknown host waits for you.
locklog Logs: masked, bounded log search; the agent reads the logs, not the people in them.
lockssh Commands over SSH: allow-listed commands run at once, the rest waits for you; the key never leaves the console.
lockhub The approval hub and its lox CLI: lox run approves outside the agent's harness and never sees values in clear.
lockkit The shared Go core of every Lock: console, policies, masking, signed tickets, audit, MCP.
lea Runs many agents in containers, wired to the Locks.

Contributing · Security · License

  • Contributing: CONTRIBUTING.md. Build with CGO_ENABLED=0 go build ./cmd/locklog (Go 1.26+).
  • Security: report a vulnerability privately, see SECURITY.md.
  • License: Apache License 2.0, see LICENSE and NOTICE.

Directories

Path Synopsis
cmd
locklog command
Command locklog lets an AI agent search and count across logs it never reads in clear: a console held by a human reads the logs, and the agent gets masked, bounded answers over MCP.
Command locklog lets an AI agent search and count across logs it never reads in clear: a console held by a human reads the logs, and the agent gets masked, bounded answers over MCP.
internal
agentassets
Package agentassets holds locklog's agent texts (skill, instructions, Cursor rule, example config) and their wiring through lockkit's agentwire.
Package agentassets holds locklog's agent texts (skill, instructions, Cursor rule, example config) and their wiring through lockkit's agentwire.
authproxy
Package authproxy generates an authenticating TLS proxy (Caddy) for a Loki that runs without auth in the user's Compose stack, so that a production profile can read it (design §2.5).
Package authproxy generates an authenticating TLS proxy (Caddy) for a Loki that runs without auth in the user's Compose stack, so that a production profile can read it (design §2.5).
config
Package config loads locklog profiles from the project and user config files (`.locklog/config.toml`, then the user's), applies the defaults, refuses anything that looks like a secret or that the production rules forbid, and computes the security-relevant policy of a profile.
Package config loads locklog profiles from the project and user config files (`.locklog/config.toml`, then the user's), applies the defaults, refuses anything that looks like a secret or that the production rules forbid, and computes the security-relevant policy of a profile.
doctor
Package doctor is `locklog doctor`: an advisory check of what the agent's account can reach where it runs, around the console.
Package doctor is `locklog doctor`: an advisory check of what the agent's account can reach where it runs, around the console.
egress
Package egress is the console's only way out to a remote log backend: an HTTP client whose dialer is pinned to the configured host and port, that uses no proxy and follows no redirect, sends only the requests of an allowlist (method and path, segment by segment), caps every response, and checks the server's certificate as the profile's tls mode says.
Package egress is the console's only way out to a remote log backend: an HTTP client whose dialer is pinned to the configured host and port, that uses no proxy and follows no redirect, sends only the requests of an allowlist (method and path, segment by segment), caps every response, and checks the server's certificate as the profile's tls mode says.
engine
Package engine answers the agent's log queries over masked records: it validates a query, builds a byte plan from the range and trusted selectors only, admits it against the per-call budgets, masks every record of each planned granule before any predicate runs, and stops at plan-chunk boundaries at its deadline, with a sealed cursor to continue.
Package engine answers the agent's log queries over masked records: it validates a query, builds a byte plan from the range and trusted selectors only, admits it against the per-call budgets, masks every record of each planned granule before any predicate runs, and stops at plan-chunk boundaries at its deadline, with a sealed cursor to continue.
engine/session
Package session opens the log engine of an approved policy for the console (logconsole.Opener): the masker of each source, the local index in the console's state directory, the sources the policy names (given only the mount roots the launcher checked), the keys (K_ref, pseudonym epochs), the cost model and the budgets, and serves the agent's methods over it.
Package session opens the log engine of an approved policy for the console (logconsole.Opener): the masker of each source, the local index in the console's state directory, the sources the policy names (given only the mount roots the launcher checked), the keys (K_ref, pseudonym epochs), the cost model and the budgets, and serves the agent's methods over it.
hostfacts
Package hostfacts holds what `locklog profile add` and `locklog doctor` know of the machine the agent runs on: its account (euid, groups, sudo), Docker's reach, the log files and journals, the containers and the installed agents.
Package hostfacts holds what `locklog profile add` and `locklog doctor` know of the machine the agent runs on: its account (euid, groups, sudo), Docker's reach, the log files and journals, the containers and the installed agents.
index
Package index is the local index of file streams: for each plan granule of a stream, its record count, its time span, and per-minute counts of the tuples of the source's trusted low-cardinality fields.
Package index is the local index of file streams: for each plan granule of a stream, its record count, its time span, and per-minute counts of the tuples of the source's trusted low-cardinality fields.
landlock
Package landlock confines the console's own file access with Landlock (Linux >= 5.13): once Restrict ran, the process (every thread) may only read beneath the read-only roots, read and execute beneath the exec roots, and write only beneath the read-write ones.
Package landlock confines the console's own file access with Landlock (Linux >= 5.13): once Restrict ran, the process (every thread) may only read beneath the read-only roots, read and execute beneath the exec roots, and write only beneath the read-write ones.
logconsole
Package logconsole is locklog's console backend for lockkit: the agent's log methods (log.status, log.sources, log.search, log.count, ...), the checks the console makes before it opens a log (the mount roots and the .locklog directory the launcher checked, no network it was not given), the policy of a profile, and the audit record of every call.
Package logconsole is locklog's console backend for lockkit: the agent's log methods (log.status, log.sources, log.search, log.count, ...), the checks the console makes before it opens a log (the mount roots and the .locklog directory the launcher checked, no network it was not given), the policy of a profile, and the audit record of every call.
mask
Package mask turns raw events into masked records, the only form of log content that leaves the console (design §4).
Package mask turns raw events into masked records, the only form of log content that leaves the console (design §4).
mask/masktest
Package masktest generates seeded log corpora with planted canaries (synthetic personal values and secrets, in every position and encoding) and scans bytes for any of them: the leak harness of design §4.7.
Package masktest generates seeded log corpora with planted canaries (synthetic personal values and secrets, in every position and encoding) and scans bytes for any of them: the leak harness of design §4.7.
mcptools
Package mcptools is locklog's MCP server: one tool per log method of the console, each a thin adapter over the console's socket.
Package mcptools is locklog's MCP server: one tool per log method of the console, each a thin adapter over the console's socket.
mountplan
Package mountplan turns a profile's local sources into the mount plan the launcher applies on the host: one line per directory to bind read-only into the console, with the globs the console may open under it.
Package mountplan turns a profile's local sources into the mount plan the launcher applies on the host: one line per directory to bind read-only into the console, with the globs the console may open under it.
parse
Package parse turns raw log bytes into events: it reads bounded lines, assembles multi-line events (stack traces) under the event caps, and decodes each event's format into a structured tree with exact numbers.
Package parse turns raw log bytes into events: it reads bounded lines, assembles multi-line events (stack traces) under the event caps, and decodes each event's format into a structured tree with exact numbers.
product
Package product declares locklog's names for lockkit.
Package product declares locklog's names for lockkit.
setup
Package setup is `locklog profile add`: a profile of the project's .locklog/config.toml from what the host holds (log files with their rotated and compressed siblings, the journal, the running containers, a Compose Loki), the production question, and the authenticating proxy of a Compose Loki.
Package setup is `locklog profile add`: a profile of the project's .locklog/config.toml from what the host holds (log files with their rotated and compressed siblings, the journal, the running containers, a Compose Loki), the production question, and the authenticating proxy of a Compose Loki.
source
Package source defines the internal interface of log sources: the byte plan of a range, the scan of one plan chunk, and the re-read of one record by its raw position.
Package source defines the internal interface of log sources: the byte plan of a range, the scan of one plan chunk, and the re-read of one record by its raw position.
source/docker
Package docker is the Docker log source: the json-file logs of the containers whose names the human approved, read from the containers root (`docker info .DockerRootDir` + /containers, bound read-only and non-recursive by the launcher), through a name -> id map the launcher keeps current.
Package docker is the Docker log source: the json-file logs of the containers whose names the human approved, read from the containers root (`docker info .DockerRootDir` + /containers, bound read-only and non-recursive by the launcher), through a name -> id map the launcher keeps current.
source/elastic
Package elastic is the Elasticsearch (8.x) and OpenSearch (2.x) log source.
Package elastic is the Elasticsearch (8.x) and OpenSearch (2.x) log source.
source/elastic/elastictest
Package elastictest is a fake Elasticsearch 8 / OpenSearch 2 for the tests of the packages that open an Elasticsearch source (the session, the engine through it): an http.Handler over in-memory documents that answers the requests locklog sends (the root, the privilege checks, _resolve/index, _field_caps, _mapping, _settings, _count and _search with bool filters, sort, search_after and the two aggregation kinds), behind basic or API-key authentication unless Open.
Package elastictest is a fake Elasticsearch 8 / OpenSearch 2 for the tests of the packages that open an Elasticsearch source (the session, the engine through it): an http.Handler over in-memory documents that answers the requests locklog sends (the root, the privilege checks, _resolve/index, _field_caps, _mapping, _settings, _count and _search with bool filters, sort, search_after and the two aggregation kinds), behind basic or API-key authentication unless Open.
source/file
Package file is the file log source: globs of plain, gzip and zstd files under the console's read-only mount roots, read beneath their root without following symbolic links, planned in fixed granules, and indexed locally.
Package file is the file log source: globs of plain, gzip and zstd files under the console's read-only mount roots, read beneath their root without following symbolic links, planned in fixed granules, and indexed locally.
source/journald
Package journald is the journald log source: systemd journal files under the console's read-only journal roots, read by the pure-Go reader in ./journal, with a field allowlist applied before any value is read.
Package journald is the journald log source: systemd journal files under the console's read-only journal roots, read by the pure-Go reader in ./journal, with a field allowlist applied before any value is read.
source/journald/journal
Package journal reads systemd journal files (the format of systemd's JOURNAL_FILE_FORMAT.md): regular and compact layouts, XZ, LZ4 and ZSTD compressed data objects, keyed or Jenkins hashes.
Package journal reads systemd journal files (the format of systemd's JOURNAL_FILE_FORMAT.md): regular and compact layouts, XZ, LZ4 and ZSTD compressed data objects, keyed or Jenkins hashes.
source/journald/journal/journaltest
Package journaltest builds small journal files in memory for tests and fuzz seeds: header, DATA, ENTRY and chained ENTRY_ARRAY objects, regular or compact, plain or ZSTD/LZ4/XZ compressed (no hash tables: the reader does not use them).
Package journaltest builds small journal files in memory for tests and fuzz seeds: header, DATA, ENTRY and chained ENTRY_ARRAY objects, regular or compact, plain or ZSTD/LZ4/XZ compressed (no hash tables: the reader does not use them).
source/loki
Package loki is the Loki log source.
Package loki is the Loki log source.
source/loki/lokitest
Package lokitest is a fake Loki 3 for the tests of the packages that open a Loki source (the session, the engine through it): an http.Handler over in-memory entries that answers the requests locklog sends (labels, label values, query_range for streams and for the metric form, the instant metric query), with Loki's paging (limit over all streams, forward, end excluded) and categorized labels, behind basic authentication unless Open.
Package lokitest is a fake Loki 3 for the tests of the packages that open a Loki source (the session, the engine through it): an http.Handler over in-memory entries that answers the requests locklog sends (labels, label values, query_range for streams and for the metric form, the instant metric query), with Loki's paging (limit over all streams, forward, end excluded) and categorized labels, behind basic authentication unless Open.
test
hub
Package hub runs locklog's hub mode end to end in one process, as an agent meets it: the MCP tools, the console server (lockkit) with the logconsole backend and a real engine session over a log file, and lockkit's fake lockhub (hubtest), which decides the tickets.
Package hub runs locklog's hub mode end to end in one process, as an agent meets it: the MCP tools, the console server (lockkit) with the logconsole backend and a real engine session over a log file, and lockkit's fake lockhub (hubtest), which decides the tickets.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL