Skip to content
GeojoLPublic

About

Decision recall. Before an agent decides, a hook gives it similar earlier decisions and the general design principles (RAG); recall is done by code. | 决策召回。通过 hook 让 agent 做决定前, 先收到之前类似的决策和通用设计原则(RAG), 召回由代码完成

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

-verdict

verdict is a deterministic recall tool for coding-agent sessions. Before an agent acts on a new prompt, verdict looks for earlier statements in the user's own past sessions that bear on the same topic, and shows a short, dated quote with its source position. The point is to surface a decision the user already made, instead of letting the agent rediscover it or contradict it.

verdict is lexical retrieval. It tokenizes text, scores it with BM25 plus recency and project weighting, and applies a gate that decides when a hint is worth showing. No model is called, at any step. The same inputs always produce the same output, and nothing leaves the machine.

How it works

  1. verdict collect reads local transcripts and documents and writes one JSON-lines file of records (data/records.jsonl by default):
    • user-typed prompts from Claude Code and Codex sessions,
    • Write/Edit/MultiEdit calls that touch memory or instruction files (CLAUDE.md, AGENTS.md, memory/ directories),
    • Markdown documents under the document roots in the config,
    • git commits and date-stamped tags from the repositories in the config. Each record keeps its source file and line, so a quote can be traced back. Text that matches a credential pattern is never stored (see below).
  2. verdict hint takes a prompt, extracts search terms, ranks the records and decides whether anything is worth showing. Silence is the default. When it does show something, it prints one line for the person and a small reference block for the model. Shown records enter a per-session cooldown so the same record is not repeated on every turn.
  3. verdict query and verdict recall are explicit lookups with no gate and longer quotes.
  4. verdict mcp and verdict serve expose the same lookup as one MCP tool, verdict_recall, over stdio or over MCP-style HTTP.

Ranking, in brief:

  • BM25 over the record text, with the standard constants k1=1.2, b=0.75.
  • Source weights: user prompts rank above agent-written notes, which rank above documents, which rank above commits and tags.
  • Marker words raise a record's weight. The two lists (strong and medium) are in internal/verdict/record.go. They are Chinese words, so Chinese prompts get the boost and English prompts do not. A negation directly before a marker cancels it. Other languages get no marker boost unless you change the lists.
  • Recency: the hint path halves a record's weight every 30 days. Recall uses a gentler hyperbolic decay with a floor.
  • Project weighting: records from the caller's own project count double.
  • Common ASCII words (in more than 1% of candidate records) are chosen last as search terms and cannot justify a hint on their own.

Supported transcript formats

Source Location read Records
Claude Code ~/.claude/projects/*/*.jsonl user prompts (structural origin check), Write/Edit to memory and instruction files
Codex ~/.codex/sessions/**/*.jsonl user input from sessions started in the terminal UI
Git each git_repos work tree commit subjects and bodies, tags with a date in the name
Documents each doc_roots tree and ~/.claude/projects/*/memory/*.md Markdown files, with the last commit time when the file is tracked

Files are read only from these locations. Typed prompts, curated notes and documents that match a credential pattern are dropped, not stored.

Requirements and build

  • Go 1.27 or newer (see go.mod). No third-party modules are used.
  • Python 3 with the standard library only, for the optional hook shim.
go build -ldflags "-X main.version=0.0.9" -o verdict ./cmd/verdict
./verdict version

Run the Go unit tests with an isolated home and cache directory:

HOME=$(mktemp -d) GOCACHE=$(mktemp -d) go test ./...
go vet ./...

Run the hook shim tests:

HOME=$(mktemp -d) python3 -I tools/test_verdict_hook.py

CLI

verdict collect  [--out FILE] [--since DATE] [--git-repo DIR]...
                 [--doc-root DIR]... [--skip-protected]
verdict query    --as-of RFC3339 [--records FILE] [--entities FILE] [--top N]
                 [--json] [--live-session ID] [--live-transcript FILE] "<text>"
verdict hint     [--records FILE] [--seen FILE] [--top N] [--plain] [--as-of RFC3339]
verdict recall   [--records FILE] [--top N] [--json] [--as-of RFC3339] "<words>"
verdict mcp      [--records FILE]
verdict serve    [--records FILE] [--bind ADDR] [--port N] [--token-file FILE]
verdict serve    --print-addr [--json]
verdict version

Examples:

# Build the records file from your transcripts, the repositories and folders in the config.
verdict collect --out ~/.local/share/verdict/records.jsonl

# Look up a topic with explicit ranking output.
verdict recall --records ~/.local/share/verdict/records.jsonl "database migration rollback"

--as-of pins the clock for reproducible output. The environment variable VERDICT_ASOF does the same (a time, or a file that holds one).

Configuration

Every command reads one optional JSON config file at start. Its path is $VERDICT_CONFIG, or ~/.config/verdict/config.json when that is unset. A missing file means the defaults. A malformed file is an error. An annotated example is in examples/config.example.json.

Key Meaning Default
doc_roots directories searched for Markdown documents; they are also allowed as quote sources none
git_repos git work trees whose commits and tags are collected none
entities path to an entity TSV (below) used by query none
credential_patterns extra credential rules, added to the built-in ones (below) none
hook_personas when non-empty, the hook hints only sessions whose working directory's base name is listed none (every session is hinted)

Other settings:

Setting Where Default
records file --records, or VERDICT_RECORDS for hint data/records.jsonl
cooldown ledger --seen (empty disables), or VERDICT_SEEN data/hookseen.jsonl
listen address serve --bind or VERDICT_MCP_BIND 127.0.0.1
listen port serve --port 8933
bearer token serve --token-file FILE or VERDICT_MCP_TOKEN_FILE none
MCP call log VERDICT_CALL_LOG (append-only file) off
hook binary, records, state, config VERDICT_BIN, VERDICT_RECORDS, VERDICT_STATE, VERDICT_CONFIG (for the shim) verdict on PATH, ~/.local/share/verdict/records.jsonl, ~/.local/state/verdict, ~/.config/verdict/config.json

Entity list

An entity is a name that should boost the records containing it (a host, a service, a project). The file is TSV: column 1 is the entity, and an optional column 2 lists aliases separated by commas. Blank lines and lines starting with # are ignored. See examples/entities.example.tsv.

Credential patterns

Built-in patterns cover private key blocks, common token prefixes (sk-, ghp_, xox*-, AKIA...) and password: / password=. Text that matches any pattern is dropped at collect time, in typed prompts as well as notes and documents.

Add your own with credential_patterns. Each entry is one of:

  • a regular expression (Go RE2 syntax), for example acme-[0-9]{6};
  • keyword:<word>: the word, an optional separator (:, =, :, 是 or a space), then an ASCII value of at least four characters. Use it for prompt words that come before a secret, such as a Chinese word for password.

Example (the Chinese words mean password, passphrase and account password):

{
  "credential_patterns": ["keyword:密码", "keyword:口令", "keyword:账号密码"]
}

With that config, a prompt such as 密码: hunter2x is dropped, while 密码重置的流程怎么走 (no ASCII value after the word) is kept. An invalid entry fails the command with an error, and no partial list is installed.

Hook setup (Claude Code)

The shim reads the hook JSON from stdin, runs verdict hint with it, and prints the hook output. It is silent when the binary or the records file is missing, so a broken install never blocks a prompt.

Add the hook to your Claude Code settings file (~/.claude/settings.json) or to a project settings file. The path is an example:

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/verdict/tools/verdict-hook user-prompt"
          }
        ]
      }
    ]
  }
}

Put the verdict binary on PATH, or set VERDICT_BIN. Schedule verdict collect (for example from cron or a launchd job) so the records file stays current. Use --skip-protected in a background job on macOS, so that the job does not open files in the privacy-protected folders and raise a permission prompt.

MCP tool

verdict mcp speaks newline-delimited JSON-RPC on stdio. verdict serve speaks the same protocol as POST /mcp and answers GET /healthz. Both expose one read-only tool:

  • verdict_recall (input: query string, optional top integer). Returns ranked quotes with their source positions, or a "no match" line with the reason.

The tool list is defined in contract/verdict-mcp.v1.json and embedded in the binary. The result text format is part of the same contract. Changing either changes what clients see.

Example client registration for stdio (the format depends on your MCP client):

{
  "mcpServers": {
    "verdict": {
      "command": "/path/to/verdict",
      "args": ["mcp", "--records", "/path/to/records.jsonl"]
    }
  }
}

Security

See SECURITY.md for the threat model. In short:

  • Typed prompts, notes and documents that match a credential pattern are not stored. The built-in patterns can be extended with credential_patterns.
  • A quote is read only from a file under the transcript directories or a configured document root, after resolving symlinks. Any other source falls back to the text stored in the record.
  • serve binds loopback by default. A non-loopback address requires --token-file (the file must be mode 0600 or stricter). Requests with an Origin header are refused.
  • The hook reads at most 4 MiB from stdin and fails silent on any error.
  • Recalled text is untrusted data. The hint and the MCP results are not sanitized for prompt injection.

Limitations

  • Lexical only. Paraphrases with no shared terms will not match. There is no embedding index in this release.
  • Recall depends on what was collected. Records are read at collect time, so run collect again after new sessions.
  • Quotes come from your own history and may be stale or wrong. The hint says "reference only" for that reason, and the recency weighting lowers old records. Check the source before acting on a quote.
  • Chinese and other CJK text is segmented into character bigrams and corpus-derived words. There is no dictionary, so segmentation is approximate.
  • The credential filter is a regular-expression approximation. It can miss a secret that has no recognizable shape, and it can drop a document that mentions password:.
  • The records file contains your prompts. Treat it as sensitive.
  • Only the Claude Code and Codex transcript formats are read.
  • The verdict config and records are per user; there is no multi-user mode.

Tests

go test ./... covers ranking, the marker and negation rules, credential patterns (built-in and configured), config loading, quote roots, the bind rule, the stdin cap, entity loading and the contract. Test inputs are short synthetic samples. No transcript or record from a real session is used.

Related projects

These four projects were built together and can be used together. Each one also runs on its own.

Project What it does How it connects
-agents-msger Messages between agent sessions on different machines. Sender identity is detected from the process tree. Its hub lists which sessions are alive on each host (/who, /status).
-d-browser A browser pool for agents. One Chromium per caller, verified by the kernel, closed when the caller exits. Provides the pbrowse command. For a call forwarded from another machine, it asks the agents-msger hub whether that caller is still alive and closes its Chromium when it is gone.
-wsearch Search service. The calling model writes the query in several languages; fixed code runs the searches and merges the results. Its browser features (page rendering, scripts) use d-browser's pbrowse.
-verdict Decision recall. Before an agent decides, a hook gives it similar earlier decisions and the general design rules. Recall is done by code (BM25). No dependency on the others.

Using them together, in this order:

  1. agents-msger: run one hub, and one shim on every machine (see the agents-msger README, Install). Its installer writes ~/.config/mcp-msgers/config.json, which holds the hub address and the token file.
  2. d-browser: install it on the machines that run browsers. It reads that same agents-msger config to find the hub; nothing else needs to be set. Its pbrowse command is installed with it.
  3. wsearch: install it, and point PBROWSE_BIN at d-browser's pbrowse (or put pbrowse on PATH).
  4. verdict: install the hook in Claude Code (see the verdict README, Hook setup). It needs none of the others.

Project status

Version 0.0.9, with public-copy changes (configurable credential patterns and the security fixes listed in CHANGELOG.md). Licensed under MIT; see LICENSE.

About

Decision recall. Before an agent decides, a hook gives it similar earlier decisions and the general design principles (RAG); recall is done by code. | 决策召回。通过 hook 让 agent 做决定前, 先收到之前类似的决策和通用设计原则(RAG), 召回由代码完成

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages