Skip to content

feat: add Relay agent foundation and workflow recenter#25

Merged
flyingrobots merged 18 commits intomainfrom
feat/relay-agent-foundation
Mar 29, 2026
Merged

feat: add Relay agent foundation and workflow recenter#25
flyingrobots merged 18 commits intomainfrom
feat/relay-agent-foundation

Conversation

@flyingrobots
Copy link
Copy Markdown
Member

@flyingrobots flyingrobots commented Mar 29, 2026

Summary

This PR recenters git-cas around the new legends/cycles workflow and lands the first substantial Relay agent surface on top of the existing CAS/vault core.

It includes:

  • a dedicated machine-facing git-cas agent entrypoint and JSONL protocol
  • read-only Relay commands
  • write flows for store, restore, and tree
  • recipient inspection and mutation flows
  • Relay key rotation and vault passphrase rotation flows
  • Relay vault lifecycle commands (vault init, vault remove)
  • workflow/planning doc recentering around legends, cycles, backlog items, and invariants
  • integration timeout hardening needed to keep Bun and Deno green under real load

Review Order

  1. WORKFLOW.md, CONTRIBUTING.md, ROADMAP.md, STATUS.md
  2. bin/agent/protocol.js, bin/agent/cli.js, bin/git-cas.js
  3. test/unit/cli/agent-protocol.test.js, test/integration/agent-cli.test.js
  4. Relay design docs under docs/design/ and backlog/legend/invariant docs
  5. timeout hardening in test/integration/vault.test.js

Notes

This is intentionally the point where the branch stops growing and goes to review. The diff is already large enough that stacking more Relay work onto it would make review quality worse.

Verification

  • npx eslint .
  • npm test
  • docker compose run --build --rm test-node npx vitest run test/integration
  • docker compose run --build --rm test-bun bunx vitest run test/unit
  • docker compose run --build --rm test-bun bunx vitest run test/integration
  • docker compose run --build --rm test-deno deno run -A npm:vitest run test/unit
  • docker compose run --build --rm test-deno deno run -A npm:vitest run test/integration

Summary by CodeRabbit

  • New Features

    • Added an agent CLI with a JSONL protocol and machine-facing commands, plus vault diagnostics (stats/doctor) and new agent recipient/vault lifecycle commands.
  • Documentation

    • Large docs overhaul: WORKFLOW, ROADMAP, STATUS, CHANGELOG, design specs, backlog, legends, invariants, and planning/testing guidance.
  • Tests

    • New unit and integration suites validating agent protocol and end-to-end CLI flows (cross-runtime/Docker-focused).
  • Bug Fixes

    • CLI credential/passphrase edge-case fixes (ambient env ignored, reject empty/whitespace passphrases, init/algorithm validation) and launch-dashboard normalization.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 29, 2026

Warning

Rate limit exceeded

@flyingrobots has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 16 minutes and 9 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 16 minutes and 9 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 81a6b762-53fc-48d0-ac6f-f0c38ce54282

📥 Commits

Reviewing files that changed from the base of the PR and between 9e2c6ac and 46f15d1.

📒 Files selected for processing (3)
  • .gitignore
  • bin/agent/cli.js
  • test/integration/agent-cli.test.js
📝 Walkthrough

Walkthrough

Adds a JSONL-first agent CLI and protocol, many machine-facing agent commands for recipient/vault inspection and mutation, workflow/planning docs (WORKFLOW, legends, backlog, design, invariants), CLI wiring and credential/passphrase validation changes, and extensive integration/unit tests for agent protocol and vault flows.

Changes

Cohort / File(s) Summary
Top-level docs & changelog
CHANGELOG.md, CONTRIBUTING.md, ROADMAP.md, STATUS.md
Project identity renamed to @git-stunts/git-cas; CONTRIBUTING rewritten to product/workflow guidance; ROADMAP/STATUS re-scoped; CHANGELOG documents added agent commands and vault diagnostics; minor markdown spacing edits.
Workflow / Planning / invariants
WORKFLOW.md, docs/legends/..., docs/invariants/..., docs/BACKLOG/*, docs/design/*, test/cycles/README.md
Added WORKFLOW as source-of-truth, legends (RL-relay), invariants (I-001), backlog RL-001..RL-005, multiple design specs (M18/RL-*), and cycle/test guidance.
Agent CLI implementation
bin/agent/cli.js
New exported runAgentCli implementing an allowlisted agent command surface, strict arg/request/passphrase parsing (inline, @file, -), credential exclusivity rules, target resolution (--slug/--oid), and handler dispatch with structured session output.
Agent protocol & session
bin/agent/protocol.js
New JSONL agent protocol: AGENT_PROTOCOL, AGENT_EXIT_CODES, error normalization helpers, getAgentExitCode, and createAgentSession emitting typed rows (start/progress/result/needs-input/error/end) with seq/timestamping.
CLI entrypoint & helpers
bin/git-cas.js, bin/actions.js
Early agent dispatch path in bin/git-cas.js; introduced explicit vs ambient passphrase-source rules, validateCredentialSources, stricter passphrase emptiness checks; bin/actions.js adds hint codes and minor refactors/formatting.
Design & backlog docs for agent features
docs/design/*, docs/BACKLOG/RL-00*
Detailed design specs for agent contract, write flows, tree creation, and RL-001..RL-005 feature definitions (recipient list/add/remove/rotate; vault init/rotate/remove).
Tests — integration & unit
test/integration/agent-cli.test.js, test/unit/cli/agent-protocol.test.js, test/integration/vault.test.js, test/integration/vault-cli.test.js, test/cycles/*
New large Docker-gated integration suite for the agent protocol across runtimes, unit tests for protocol/session behavior and exit-code mapping, vault CLI validation tests, and minor test timeout/formating tweaks.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client/CLI
    participant Agent as Agent CLI Handler
    participant CAS as CAS Service
    participant Vault as Vault/Manifest

    Client->>Agent: runAgentCli(argv, {stdout,stderr,stdin})
    activate Agent
    Agent->>Agent: parseArgs / parseRequest (flags | `@file` | -)
    Agent->>Agent: createAgentSession(command)
    Agent->>Client: write start (stdout, seq=1)

    Agent->>CAS: resolveTarget (--slug or --oid)
    CAS->>Vault: readManifest / readEnvelope
    Vault-->>CAS: manifest/envelope
    CAS-->>Agent: manifest

    Agent->>CAS: perform action (inspect/store/restore/rotate/recipient/vault)
    CAS->>Vault: read/update/create trees, rewrap entries as needed
    Vault-->>CAS: treeOid / commitOid / result
    CAS-->>Agent: result payload

    Agent->>Client: write result (stdout, seq=2)
    Agent->>Client: write end (stdout, seq=3)
    deactivate Agent
Loading
sequenceDiagram
    participant Client as Client/CLI
    participant Agent as Agent CLI Handler
    participant CAS as CAS Service
    participant Vault as Encrypted Vault

    Client->>Agent: runAgentCli(..., --request / --old-passphrase / --new-passphrase)
    activate Agent
    Agent->>Agent: parse passphrase sources (inline | `@file` | -), validate exclusivity
    Agent->>Agent: createAgentSession()
    Agent->>Client: write start (seq=1)

    alt Missing credentials or cannot decrypt
        Agent->>Client: write needs-input (stderr, seq=2)
        Agent->>Client: write end (stdout, seq=3)
        Agent-->>Client: exitCode = AGENT_EXIT_CODES.INVALID_INPUT (2)
    else Valid passphrases
        Agent->>CAS: rotateVaultPassphrase(oldPass,newPass)
        CAS->>Vault: unwrap/rewrap entries, commit
        Vault-->>CAS: commitOid, kdfAlgorithm, rotated/skipped lists
        CAS-->>Agent: result {commitOid, rotated, skipped}
        Agent->>Client: write result (seq=2)
        Agent->>Client: write end (seq=3)
        Agent-->>Client: exitCode = AGENT_EXIT_CODES.SUCCESS (0)
    end
    deactivate Agent
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Poem

🐰 I hopped through fields of JSONL light,

I ribboned vaults and turned keys tight.
No prompts, just rows that march in line,
Recipients counted, commits that shine.
Relay hums softly — agent's design.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.99% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add Relay agent foundation and workflow recenter' accurately describes the main changes: introduction of a new agent CLI with Relay protocol and documentation/workflow restructuring.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/relay-agent-foundation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bin/git-cas.js`:
- Around line 703-708: The checks for oldPassphrase and newPassphrase only
reject undefined/null but allow whitespace-only values; update the validation to
treat blank/whitespace-only strings as missing by trimming and verifying length
(e.g., if (!oldPassphrase || !oldPassphrase.trim()) and similarly for
newPassphrase) before throwing the existing Error messages so whitespace-only
passphrases are rejected consistently with earlier validation for passphrases
like oldPassphrase and newPassphrase.
- Around line 282-288: The current conflict check in the runAction callback
incorrectly uses hasPassphraseSource(opts) which treats ambient env vars (like
GIT_CAS_PASSPHRASE) as an explicit mode and blocks --recipient; change the
condition that throws when both recipient and a passphrase source are present to
only consider CLI-provided passphrase flags (e.g. check opts.vaultPassphrase ||
opts.vaultPassphraseFile or whatever CLI option properties represent
--vault-passphrase/--vault-passphrase-file) rather than
hasPassphraseSource(opts), or alternatively update hasPassphraseSource to
distinguish explicit CLI flags from environment variables so that opts.recipient
and opts.keyFile are only considered conflicting with an explicitly-provided
passphrase flag.

In `@CONTRIBUTING.md`:
- Around line 227-233: Replace the `pnpm run lint` guidance with the canonical
ESLint invocation used by the gate: instruct contributors to run `npx eslint .`
(ensuring it targets the code globs `**/*.{js,ts,jsx,tsx}`) and state that
ESLint must pass with zero errors; update the Local testing policy entry that
currently references `pnpm run lint` to this canonical command and requirement.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c340d27b-1936-43b5-8eb1-4dec792b8d35

📥 Commits

Reviewing files that changed from the base of the PR and between 20305f0 and bfaef96.

📒 Files selected for processing (32)
  • CHANGELOG.md
  • CONTRIBUTING.md
  • ROADMAP.md
  • STATUS.md
  • WORKFLOW.md
  • bin/actions.js
  • bin/agent/cli.js
  • bin/agent/protocol.js
  • bin/git-cas.js
  • docs/BACKLOG/README.md
  • docs/BACKLOG/RL-001-agent-recipient-list.md
  • docs/BACKLOG/RL-002-agent-recipient-mutations.md
  • docs/BACKLOG/RL-003-agent-rotate.md
  • docs/BACKLOG/RL-004-agent-vault-rotate.md
  • docs/BACKLOG/RL-005-agent-vault-lifecycle.md
  • docs/design/0001-m18-relay-agent-cli.md
  • docs/design/0002-m18-relay-write-flows.md
  • docs/design/0003-m18-relay-tree-creation.md
  • docs/design/README.md
  • docs/design/RL-001-agent-recipient-list.md
  • docs/design/RL-002-agent-recipient-mutations.md
  • docs/design/RL-003-agent-rotate.md
  • docs/design/RL-004-agent-vault-rotate.md
  • docs/design/RL-005-agent-vault-lifecycle.md
  • docs/invariants/I-001-determinism-trust-and-explicit-surfaces.md
  • docs/invariants/README.md
  • docs/legends/README.md
  • docs/legends/RL-relay.md
  • test/cycles/README.md
  • test/integration/agent-cli.test.js
  • test/integration/vault.test.js
  • test/unit/cli/agent-protocol.test.js

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bin/agent/cli.js`:
- Around line 818-823: Update the JSDoc for parseVaultRotateInput to match the
actual parameter names and types: change the first `@param` from "input" to "args"
and set its type to string[] (or the correct type used in the function), keep
the second `@param` as stdin with type NodeJS.ReadStream, and ensure the `@returns`
annotation matches the function's returned type; reference the function name
parseVaultRotateInput when making these edits.
- Around line 439-474: Update the JSDoc for readAgentPassphraseFile to document
the second options parameter: add a `@param` {Object} options description (or
`@param` {{stdin?: import('stream').Readable, onWarning?: function}} options) that
lists stdin (a Readable stream used when filePath === '-') and onWarning
(optional callback invoked with a warning object {code, message, filePath,
recommendation}); keep the existing `@param` {string} filePath and `@returns`
{Promise<string>} intact so the signature matches the actual function async
function readAgentPassphraseFile(filePath, { stdin, onWarning } = {}).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2ef990fb-7a5f-4ce0-9f08-2408c02d40d0

📥 Commits

Reviewing files that changed from the base of the PR and between bfaef96 and c4836e2.

📒 Files selected for processing (2)
  • bin/agent/cli.js
  • test/integration/agent-cli.test.js

@flyingrobots
Copy link
Copy Markdown
Member Author

@coderabbitai review please 🥕

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 29, 2026

@flyingrobots Sure thing! Kicking off the review now 🐰

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bin/agent/cli.js`:
- Around line 371-395: parseAgentInput currently merges the parsed JSON request
payload from readRequestPayload directly into values, allowing improperly-typed
fields to bypass parseArgs validation; fix it by validating and coercing the
request object before merging: after calling readRequestPayload(request, stdin)
use the existing parseArgs/REQUEST_OPTION schema or explicit type checks to
ensure each expected option (e.g., boolean flags like "tree" and "force" and
string path fields) has the correct type, coerce string booleans
("true"/"false") to actual booleans, reject or normalize non-string path values,
and only then spread the sanitized request into values; keep requestSource as
parsed.values.request but do not merge raw request without this validation.

In `@bin/git-cas.js`:
- Around line 117-126: The helper hasExplicitPassphraseSource currently treats
empty strings as absent; change validation to detect presence of the flags
themselves (not truthiness) and treat an explicit empty string as provided so
CLI rejects conflicting inputs—update hasExplicitPassphraseSource to check for
keys in opts (e.g., Object.prototype.hasOwnProperty.call(opts,
'vaultPassphrase') or 'vaultPassphraseFile') and ensure the store/restore
command paths (the handlers that inspect opts for key-file, vaultPassphrase,
vaultPassphraseFile) validate and throw an error when both --key-file and any
vault passphrase flag are present; apply the same presence-based check in all
locations mentioned (hasExplicitPassphraseSource and the store/restore option
checks).
- Around line 521-539: The command currently allows specifying --algorithm
(opts.algorithm) but then silently proceeds with an unencrypted init when
resolvePassphrase(...) returns no passphrase; fix by refusing to proceed if an
algorithm was explicitly provided but no passphrase was obtained: after
computing passphrase = await resolvePassphrase(opts, { confirm: true }), if
(!passphrase && opts.algorithm) throw a user-facing error (or exit non-zero)
explaining that --algorithm requires a passphrase (use --vault-passphrase,
--vault-passphrase-file, or run interactively), and ensure initOpts.kdfOptions
is only set when passphrase is present (keep createCas and initOpts logic intact
otherwise).

In `@CONTRIBUTING.md`:
- Around line 49-50: Update the contributor docs to reflect that the "git cas
agent" command is shipped (not future): change phrasing in the bullets that
currently read "keep every human CLI command machine-readable through `--json`"
and "keep the future `git cas agent` surface JSONL-first and non-interactive" so
they state that "git cas agent" is available and its surface is JSONL-first and
non-interactive; update any other occurrences (e.g., the second block
referencing `git cas agent`) to remove future/planned language and use
present-tense wording indicating the command is implemented and follows the
JSON/JSONL non-interactive convention.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b7fc2969-583d-49a2-a81f-df0e7b4074ed

📥 Commits

Reviewing files that changed from the base of the PR and between c4836e2 and ccf6b69.

📒 Files selected for processing (6)
  • CHANGELOG.md
  • CONTRIBUTING.md
  • bin/agent/cli.js
  • bin/git-cas.js
  • test/integration/agent-cli.test.js
  • test/integration/vault-cli.test.js

@flyingrobots
Copy link
Copy Markdown
Member Author

@coderabbitai review please 🥕

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 29, 2026

@flyingrobots Sure thing! Kicking off the review now 🥕🐰

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@flyingrobots flyingrobots merged commit 6df6e86 into main Mar 29, 2026
3 checks passed
@flyingrobots flyingrobots deleted the feat/relay-agent-foundation branch March 29, 2026 21:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant