Metadata-Version: 2.4
Name: monogate-capcard-cli
Version: 1.0.0
Summary: Persistent identity + verification CLIs for Monogate CapCard agents
Author-email: Monogate <almaguer1986@gmail.com>
License: Apache-2.0
Project-URL: Homepage, https://capcard.ai
Project-URL: Source, https://github.com/agent-maestro/capcard-cli
Keywords: monogate,capcard,agents,verification,trust
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Dynamic: license-file

# capcard-cli

Persistent identity + weighted-trust verification + knowledge
transfer + cross-agent attestation + RL training-data extraction +
cross-registry wire format for Monogate CapCard agents. All seven
phases of the [CapCard: Verified Agents](https://capcard.ai)
roadmap — turns anonymous Claude Code sessions into named agents
with stable IDs + generation lineage, evidence-backed verification
records scored on a Lean-proof-to-self-report scale, structured
session-end playbooks the next agent on a related task can read, a
"builder posts / verifier signs / both trust scores update"
cross-attestation flow so trust is earned, a training-data export
pipeline that turns the accumulated playbook archive into shaped-
reward episodes for an RL agent training loop, and a stable JSON
wire format with idempotent merge for cross-registry sync.

> **All phases shipped (1.0.0).** Twelve binaries on PATH:
> `capcard-register` (with `--generation` / `--parent` /
> `--pubkey`), `capcard-status`, `capcard-verify` (with
> `--evidence-type` and `--needs-attestation`), `capcard-attest`
> (`--pass` / `--reject` / `--dispute`), `capcard-attestations`
> (`--pending` / `--by` / `--on`), `capcard-recompute-trust` (with
> `--iterative` and `--dispute-decay-days`), `capcard-playbook`
> (`generate` / `show` / `search`), `capcard-export`,
> `capcard-tactics`, `capcard-stats`, `capcard-bundle`
> (`export` / `import`), `capcard-fingerprint`. Trust is the
> weighted formula `sum(w_i) / sum(|w_i|)` clamped to `[0, 1]`,
> with cross-attestation gating contribution when the builder
> requests it. Disputes resolve by quorum (≥2 distinct
> non-disputers agreeing); per-verifier votes collapse; stale
> dispute markers can be aged out with `--dispute-decay-days`.
> Phase 5 turns the playbook archive into shaped-reward episodes
> for an RL pipeline. Phase 7 ships a versioned JSON wire format
> ready for a future network gossip layer (the actual gossip + ZK
> proofs are an out-of-CLI research project — see
> [`docs/BACKLOG.md`](docs/BACKLOG.md)).

## Install

```bash
git clone https://github.com/agent-maestro/capcard-cli   # once on PyPI: pip install monogate-capcard-cli
cd capcard-cli
pip install -e .
```

The package depends on nothing outside the Python stdlib — installs
into any Claude Code session's Python without dragging in a wider
requirements graph.

## Use

### Register at session start

```bash
capcard-register --name "Frontier C Researcher" \
                 --role researcher \
                 --task "Galois dimension proof"
```

Roles: `researcher`, `builder`, `tooling`, `verifier` (any other
string is accepted with a warning to stderr — extensible without
a registry migration).

The first registration with a given `--name` allocates an
`agent_id` slug (`researcher-001`, `builder-001`, etc.). Subsequent
calls with the same name return the same ID and update
`current_task` + `last_active`.

### Update mid-session

```bash
capcard-status --agent researcher-001 \
               --task "writing arXiv update" \
               --status working
```

Status values: `working`, `idle`, `blocked`, `done`, `failed`
(also extensible).

### List

```bash
capcard list
capcard list --json    # machine-readable
```

### Verify a unit of work

`capcard-verify` records one outcome with cryptographic evidence,
appends a row to the verification log, and updates the agent's
trust counters. The agent owns the framing — `capcard-verify` is
how they sign their claim into the log.

```bash
# Treat --evidence as a literal artifact (you've already collected it)
capcard-verify --agent researcher-001 \
               --evidence "lake build clean (12/12 modules)" \
               --result proof-closed \
               --theorem tanh_monotone

# Have capcard-verify execute the evidence command and capture the result
capcard-verify --agent builder-001 \
               --evidence "pytest -q" \
               --result feature-shipped \
               --run

# Honest-negative: investigation that returned a negative finding.
# Counts as a verified outcome — does NOT decrease trust.
capcard-verify --agent researcher-001 \
               --evidence "C-246 NOTES.md: Phi homomorphism is trivial" \
               --result honest-negative

# Failure: shipped broken code, broke CI, false-claim correction.
# Decreases trust.
capcard-verify --agent builder-001 \
               --evidence "CI red on main: type signature regression" \
               --result failure
```

The result types and their effect on the simple counter pair (the
weighted trust score uses the `--evidence-type` table below — see
"Phase 4: weighted trust"):

| `--result`             | Counter bumped       | Trust direction        |
|------------------------|----------------------|------------------------|
| `proof-closed`         | `verified_outputs`   | up                     |
| `feature-shipped`      | `verified_outputs`   | up                     |
| `theorem-established`  | `verified_outputs`   | up                     |
| `bug-fixed`            | `verified_outputs`   | up                     |
| `honest-negative`      | `verified_outputs`   | up (per spec)          |
| `failure`              | `failed_outputs`     | down                   |

### Phase 4: weighted trust

`capcard-verify` accepts an optional `--evidence-type` that drives
the weighted trust formula. Heavier weights mean stronger evidence:
a Lean proof checked by `lake build` is unforgeable (1.0), a self-
report is just the agent's word (0.2). Negative weights model
verifiable harm.

| `--evidence-type` | Weight | When to use                                       |
|-------------------|-------:|---------------------------------------------------|
| `lean-proof`      |  +1.0  | Lean proof passed `lake build` cleanly            |
| `bfs-closure`     |  +0.9  | BFS proof engine closed a sorry; lake-verified    |
| `test-suite`      |  +0.7  | Full test suite passed                            |
| `ci-green`        |  +0.6  | CI green (depends on test quality)                |
| `empirical`       |  +0.5  | N/N empirical hold; suggestive, not proven        |
| `honest-negative` |  +0.5  | Investigated; reported negative finding honestly  |
| `self-report`     |  +0.2  | No independent verification                       |
| `ci-broken`       |  -0.3  | Agent broke CI                                    |
| `false-claim`     |  -0.5  | Agent's earlier claim was corrected               |

```bash
# 47/47 spot-check is empirical, not a proof — be explicit
capcard-verify --agent researcher-001 \
               --evidence "47/47 holds across [501, 2000]" \
               --result theorem-established \
               --evidence-type empirical

# BFS engine closed a Discovered/ sorry
capcard-verify --agent tooling-001 \
               --evidence "tools/sweep closed exp_strict_mono_at_zero" \
               --result proof-closed \
               --evidence-type bfs-closure
```

When `--evidence-type` is omitted, the type is inferred from the
result + evidence keywords (`lake build` → `lean-proof`, `pytest …
passed` → `test-suite`, "ci"/"broke"/"build" tokens in a `failure`
→ `ci-broken`, etc.). Pass it explicitly when the heuristic is
wrong — the conservative default is `self-report` (0.2) for
positive results without obvious signal.

**Trust formula:** `trust = sum(w_i) / sum(|w_i|)` over all
verifications, clamped to `[0, 1]` from below. An empty history
returns 0.0 ("no track record"). The cached `trust_score` field on
the registry row is updated by every `record_verification` call;
operators can rebuild it from the log via `recompute_trust(agent_id)`
after a weight-table change.

`--run` shells out via `shlex.split` (no shell interpolation —
quote your arguments) and captures `exit_code`, wall-clock
`runtime_s`, full `stdout` + `stderr`, and a SHA-256 digest of
the combined output. `--timeout-s` defaults to 600s. If
`--run` finishes with a non-zero exit but you claimed a positive
result, the record is written as you stated it but a note is
attached so a Phase 6 verifier can spot the mismatch.

When `--run` is *not* set, `--evidence` is stored verbatim and
the digest is `sha256(evidence)`.

## What it stores

A single JSON file at `~/.agent-registry.json` (override via
`CAPCARD_REGISTRY_PATH`):

```json
{
  "version": 1,
  "agents": {
    "researcher-001": {
      "agent_id": "researcher-001",
      "name": "Frontier C Researcher",
      "role": "researcher",
      "status": "working",
      "current_task": "Galois dimension proof",
      "total_tasks": 0,
      "verified_outputs": 0,
      "failed_outputs": 0,
      "trust_score": 0.0,
      "created": "2026-05-04T13:30:00Z",
      "last_active": "2026-05-04T13:30:00Z",
      "playbook_path": null
    }
  }
}
```

Writes are atomic (temp-file-then-rename) and serialized via
`flock` on a sidecar `~/.agent-registry.json.lock`. Two parallel
`capcard-register` calls cannot lose updates.

### Phase 6: cross-agent attestation

By default `capcard-verify` self-attests — the agent's claim
contributes to their own trust immediately. Phase 6 adds a
two-step path so a verifier can confirm or reject another agent's
work before it counts.

```bash
# Builder records a pending verification (--needs-attestation).
# The record lands in the 'pending' state and contributes 0 to
# trust until cross-attested.
capcard-verify --agent builder-001 \
               --evidence "pytest -q && cargo test --release" \
               --result feature-shipped \
               --evidence-type test-suite \
               --needs-attestation
# Output ends with:
#   id:            6f00d02d4244     ← capture this
#   attestation:   pending (--needs-attestation set)

# A verifier (must be a different agent) signs off:
capcard-attest --verification-id 6f00d02d4244 \
               --verifier-agent verifier-001 \
               --pass \
               --evidence "reviewed diff + ran pytest myself" \
               --note "looks clean"
```

Outcomes:

| flag        | effect on builder trust                                                                                  | effect on verifier trust                  |
|-------------|----------------------------------------------------------------------------------------------------------|-------------------------------------------|
| `--pass`    | record contributes `base_weight × max(0.5, verifier_trust)` to the numerator (denom stays at base_weight) | +0.6 weight (review work is real work)    |
| `--reject`  | record treated as false-claim against builder (-0.5 weight)                                              | +0.6 weight                               |
| `--dispute` | record held in `disputed` state (contributes 0) until quorum resolves it (Phase 6.5)                     | +0.6 weight                               |

Guards:

- **No self-grading** — `--verifier-agent` must be different from
  the builder. Same-agent attestation returns exit 2.
- **Cross-attesting a self-attested record** returns exit 2 — the
  builder must opt in via `--needs-attestation`.
- **Verifier must be registered** — needed so the trust snapshot
  has a real value to reference.

The append-only attestation log lives at
`~/.capcard/attestations.jsonl` (override with
`CAPCARD_ATTESTATION_LOG_PATH`). Overturning a previous decision
means recording a *new* attestation, not editing the old row.

### Phase 6.5: dispute resolution + trust hygiene

The state machine resolves disputes by **quorum** instead of holding
disputed records open forever. Two rules:

1. **Per-verifier vote collapse.** A verifier who casts multiple
   attestations on the same record contributes one current vote —
   their latest stance. Flip-flopping doesn't manufacture extra
   votes (the append-only log preserves the audit trail for
   `capcard-attestations --on <vid>`).
2. **Dispute quorum.** A `dispute` marker is overridden when ≥2
   distinct non-disputer verifiers' current votes agree on the same
   verdict and that verdict has a strict majority among non-disputer
   votes. Examples:

   | non-disputer current votes | result      |
   |----------------------------|-------------|
   | pass                       | disputed    |
   | pass + pass                | confirmed   |
   | pass + reject              | disputed    |
   | pass + pass + reject       | confirmed   |
   | pass + pass + reject + reject | disputed |

```bash
# Read-only views of the attestation log + pending queue.
capcard-attestations --pending                  # awaiting cross-attestation
capcard-attestations --by verifier-001          # what this verifier signed
capcard-attestations --on 6f00d02d4244          # full audit trail on one record
```

**Trust hygiene.** Cross-attestation snapshots the verifier's
trust *at attestation time* into the row. If the verifier's trust
later changes (e.g. they made a string of bad calls), builder
records they confirmed keep the old modulator. Run
`capcard-recompute-trust` to propagate the change:

```bash
# Default: re-walk the log using snapshots (cheap).
capcard-recompute-trust --all

# Hygiene mode: re-walk using each verifier's *current* cached
# trust as the modulator. With --all we do a 2-pass converge so
# verifier scores stabilise before they're used as modulators on
# builder rows.
capcard-recompute-trust --all --use-current-verifier-trust
```

The library API (`capcard_cli.verify.recompute_trust`,
`recompute_all_trust`) takes the same `use_current_verifier_trust`
flag — useful for daemons that want to schedule periodic hygiene
runs without shelling out.

### Phase 5: training-data extraction + agent lineage

The CLI doesn't train RL agents — it makes the CapCard archive
*trainable*. Three primitives:

```bash
# Lineage. Generation auto-increments from --parent.
capcard-register --name bfs-engine-v2 --role researcher \
                 --parent researcher-001
# (researcher-002 → generation 2, parent_id=researcher-001)

# Walk the parent chain, root → leaf:
capcard list --by-lineage researcher-002
# Or every descendant of an ancestor:
capcard list --descendants-of researcher-001

# Training-data export — one shaped-reward episode per playbook.
capcard-export --role researcher --format jsonl > episodes.jsonl
capcard-export --since 2026-04-01T00:00:00Z --out training.jsonl

# Tactic effectiveness across every playbook on disk, ranked by
# (trust-weighted worked) - 0.5 * (trust-weighted failed).
capcard-tactics --on-goal "0 <= exp x" --limit 5

# Aggregate per-agent stats + evidence-type histogram. Useful to
# see whether a generation is graduating from self-report to
# lean-proof / test-suite over time.
capcard-stats --role researcher --by-generation
```

**Reward shaping** (`reward_for_playbook`):

    base    = clamp(pb.trust_delta, -1, 1)
    bonus   = +0.2  if any verification in the playbook window has
              result = "honest-negative" with non-empty evidence
    penalty = -0.3  if any verification in window has
              evidence_type = "ci-broken"
    reward  = clamp(base + bonus + penalty, -1, 1)

Bonuses and penalties stack independently; a session that ships an
honest negative AND broke CI nets to `trust_delta - 0.1`. The
clamp at the end keeps the RL pipeline's reward bounded.

**Library API** (`capcard_cli.training`) — importable from RL
training scripts:

| function                       | purpose                                                         |
|--------------------------------|-----------------------------------------------------------------|
| `reward_for_playbook(pb)`      | shaped scalar reward in `[-1, 1]`                               |
| `episode_for_playbook(pb)`     | flatten one playbook into an `Episode`                          |
| `export_episodes(role=, ...)`  | iterator over every playbook, optionally filtered               |
| `tactic_score(t, on_goal=)`    | scalar score for one tactic                                     |
| `rank_tactics(on_goal=, ...)`  | top-N tactics ranked by trust-weighted success                  |
| `agent_stats(role=, since=)`   | per-agent rollup (sessions, cumulative_reward, avg_reward)      |
| `evidence_type_histogram(...)` | rollup of evidence types from the verification log              |

Generation lineage is stored on the `AgentRecord` itself —
`generation: int` (defaults to 1, or `parent.generation + 1`) and
`parent_id: str | None`. Lineage is locked in on first registration
for a given `--name`; subsequent re-registrations don't change it
(fork a new lineage with a new name instead).

### Phase 7: cross-registry wire format

The CLI doesn't run the network gossip layer (that's a separate
project — see [`docs/BACKLOG.md`](docs/BACKLOG.md)). What it does
provide is a **stable, versioned JSON wire format** + an
idempotent merge importer, ready for a future gossip layer to
serialize over.

```bash
# Snapshot the local state into one JSON document.
capcard-bundle export --out snapshot.json --source-id "lab-monogate"

# Merge into another registry. Idempotent on primary keys
# (agent_id, verification_id, attestation_id, (agent_id, session_id)).
# Local state is authoritative — conflicts are logged and skipped,
# never overwritten.
capcard-bundle import snapshot.json
capcard-bundle import snapshot.json --dry-run     # preview only
capcard-bundle import snapshot.json --json        # ImportSummary as JSON

# Verify a verification record's stored output digest matches a
# fresh re-run of the original evidence command. Poor-man's
# "did this happen" check without ZK proofs.
capcard-fingerprint --verification-id 6f00d02d4244 --rerun
# → MATCH (exit 0) | MISMATCH (exit 3) | unknown id (exit 1)
```

The bundle format is a single JSON object with `bundle_version`,
`created`, `source_id`, and arrays of agents / verifications /
attestations / playbooks. After import, every agent's
`trust_score` is recomputed under the same lock so newly-merged
verifications and attestations propagate into the cached score.

`AgentRecord` carries an optional `pubkey: str | None` field
(`capcard-register --pubkey "..."`). It's forward-reserved — the
stdlib-only constraint means the CLI doesn't sign anything yet.
The field is here so a Phase 7+ network protocol that *does* sign
can import bundles without a schema migration.

### Phase 6.7: dispute time-decay + iterative trust converge

Two hygiene knobs on `capcard-recompute-trust` close the open
edges from the Phase 6.5 review:

```bash
# Stale disputes (latest dispute attestation older than N days)
# are ignored, letting the underlying verdict surface. Useful when
# nobody followed up on a contested record.
capcard-recompute-trust --all --dispute-decay-days 7

# Iterative converge to a fixed point. Default 2-pass already
# handles the common case; --iterative is for verifier↔verifier
# review chains that could oscillate. Stops when the L-infinity
# per-agent delta drops below --epsilon (default 0.001) or
# --max-iter (default 10) is hit.
capcard-recompute-trust --all --use-current-verifier-trust \
                        --iterative --epsilon 0.0001
```

Both flags are off by default so the conservative Phase 6.5
semantics still apply unless the operator opts in.

### Generate a session-end playbook

When the agent finishes a session (or hits a meaningful checkpoint),
`capcard-playbook generate` writes a structured summary to disk and
points the agent's `playbook_path` at the new file. The trust delta,
verification window, and result_summary are computed automatically
from the verification log since the agent's previous playbook.

```bash
capcard-playbook generate --agent researcher-001 \
    --result theorem-established \
    --lesson "P(tuple) undefined at depth >= 2" \
    --lesson "OfScientific vs OfNat blocks proofs" \
    --tactic-worked "exact exp_nonneg _||0 <= exp x" \
    --tactic-failed "trivial||0 <= exp x" \
    --artifact "machlib:9589804" \
    --open-question "depth-2 unfold under products?"
```

`--tactic-worked` / `--tactic-failed` use a literal `||` separator
between tactic and goal-shape label (the goal label is what the BFS
engine keys on — keep it consistent across sessions).

For bulk input, write the same fields to a JSON file and pass
`--from-file`. Per-flag values are merged on top:

```bash
cat > playbook.json <<'JSON'
{
  "lessons": ["P(tuple) undefined at depth >= 2"],
  "tactics_that_worked": [
    {"tactic": "exact exp_nonneg _", "on_goal": "0 <= exp x"}
  ],
  "tactics_that_failed": [
    {"tactic": "trivial", "on_goal": "0 <= exp x"}
  ],
  "artifacts": ["machlib:9589804"],
  "open_questions": ["depth-2 unfold under products?"]
}
JSON

capcard-playbook generate --agent researcher-001 \
    --result theorem-established \
    --from-file playbook.json
```

### Search prior playbooks (transfer)

When a new agent picks up a related task, search the playbook
archive for what's already been tried — the highest-leverage
transfer is the list of tactics that *failed*, so future agents
don't repeat them.

```bash
# Find related work — score is the count of distinct query terms
# matched across task / lessons / tactics / open_questions.
capcard-playbook search --task "Galois dimension proof for chain order"

# Filter to one role + tighten the score floor
capcard-playbook search --task "exp_strict_mono on negative inputs" \
                        --role researcher --min-score 2

# Machine-readable for piping into another agent's context
capcard-playbook search --task "..." --json | jq '.[0].playbook'
```

The transfer mechanism is **explicit, not magic** — the calling
agent runs the search and decides what to load. (Hidden auto-load
on `capcard-register` would silently change session behavior, which
we don't want.)

### Show / inspect

```bash
capcard-playbook show --agent researcher-001        # newest playbook
capcard-playbook show --path /path/to/playbook.json # specific file
```

### Verification log

`capcard-verify` appends one JSONL row per call to
`~/.capcard/verifications.jsonl` (override via
`CAPCARD_VERIFY_LOG_PATH`):

```json
{"agent_id":"researcher-001","evidence":"lake build","exit_code":null,
 "notes":null,"output_digest":"d41d8cd9...","ran":false,
 "result":"proof-closed","runtime_s":null,"task":"Galois dimension proof",
 "theorem":"tanh_monotone","timestamp":"2026-05-04T13:30:00Z"}
```

The log is append-only and serialized under its own flock
(`~/.capcard/verifications.jsonl.lock`). The registry stores the
rolled-up counters; the log keeps the per-event detail Phases 3
(playbook), 6 (cross-verify), and 7 (ZK fingerprints) need.

## Wire it into a Claude Code session

Add to your shell rc (or per-project `.envrc`):

```bash
# At session start, register and capture the assigned agent_id
export CAPCARD_AGENT_ID=$(capcard-register \
  --name "$USER on $(hostname -s)" \
  --role researcher \
  --json | python -c 'import json,sys; print(json.load(sys.stdin)["agent_id"])')

# Then any time you switch tasks
capcard-status --agent "$CAPCARD_AGENT_ID" --task "$NEW_TASK_DESC"

# When you finish a unit of work, log the outcome with evidence
capcard-verify --agent "$CAPCARD_AGENT_ID" \
               --evidence "lake build" \
               --result proof-closed \
               --theorem tanh_monotone \
               --run
```

Once the Command Center's `/agents` page is updated to read the
extended `blackwell-agent` `/agents` endpoint (which already merges
the registry with live tmux sessions as of this commit), the
registered agent appears with its persistent ID, role, and trust
score alongside the anonymous tmux sessions on the same machine.

## What's coming next

Per the [vision doc](https://capcard.ai/whitepaper) :

- **Phase 2 (`capcard-verify`)** — **shipped in 0.2.0**: log work
  outcomes with cryptographic evidence (`lake build` passing,
  `pytest 87 passed`, CI red). Bumps `verified_outputs` /
  `failed_outputs` per the result-type contract; appends a row to
  `~/.capcard/verifications.jsonl`.
- **Phase 3 (`capcard-playbook`)** — **shipped in 0.3.0**: emit a
  structured summary at session end (lessons / tactics_that_worked
  / tactics_that_failed / open_questions); next agent inherits via
  `capcard-playbook search`.
- **Phase 4 — weighted trust** — **shipped in 0.4.0**: replaces the
  simple `verified / total` ratio with the weight table above.
  `--evidence-type` declares what kind of proof the agent has;
  trust is the weighted average clamped to `[0, 1]`.
- **Phase 6 — cross-agent attestation** — **shipped in 0.5.0**:
  `--needs-attestation` + `capcard-attest`. Builder = verifier
  rejected; verifier trust modulates the builder's contribution
  with a 0.5 floor.
- **Phase 6.5 — dispute resolution + trust hygiene** — **shipped
  in 0.6.0**: per-verifier vote collapse, dispute quorum
  resolution (≥2 distinct non-disputers agreeing override the
  dispute), `capcard-attestations` (`--pending` / `--by` /
  `--on`), `capcard-recompute-trust` with optional
  `--use-current-verifier-trust` mode for propagating verifier-
  trust changes back into builder rows.
- **Phase 5 — RL training-data extraction** — **shipped in 0.7.0**:
  generation/parent_id on AgentRecord, `capcard-export` (shaped-
  reward episodes), `capcard-tactics` (trust-weighted ranking),
  `capcard-stats` (per-agent rollup + evidence histogram). The CLI
  doesn't train models — it makes the archive trainable.
- **Phase 6.7 — trust hygiene** — **shipped in 1.0.0**: time-decay
  for stuck dispute markers, iterative fixed-point converge in
  `recompute_all_trust`. Both opt-in via flags on
  `capcard-recompute-trust`.
- **Phase 7 — wire format + fingerprint verify** — **shipped in
  1.0.0**: `capcard-bundle export/import` (versioned, idempotent
  merge), `capcard-fingerprint --rerun` for spot-checking imported
  output digests, `pubkey: str | None` field on AgentRecord. The
  *actual* network gossip layer + ZK proofs are an independent
  research project — see [`docs/BACKLOG.md`](docs/BACKLOG.md).

The capcard-cli pipeline is feature-complete for the whitepaper
roadmap as of 1.0.0. Future work (signing, gossip, ZK
fingerprints, network resilience) belongs to the network/protocol
side of the project, not this CLI.

## Testing

```bash
pip install -e '.[dev]'
python -m pytest
```

244 tests cover: schema, atomic writes, file locking under 20-process
contention, idempotency, role-migration discipline, evidence-weight
math, playbook windowing, attestation state machine + dispute
quorum resolution + time-decay, two-pass and iterative trust
converge, lineage walkers, reward shaping (incl. clamps and
bonus/penalty stacking), tactic ranking across playbooks, episode
export filters, bundle round-trip + idempotent merge + conflict
preservation, fingerprint match/mismatch, and CLI surface.

## License

Apache-2.0 (matches the rest of the Monogate stack).
