Skip to content

Repository files navigation

cq

This flake packages the ledger suite: an MCP server plus terminal and browser frontends. The coding-agent packages, settings, and yolo sandbox live in the separate ponygirls flake. CQ imports it and adds the ledger MCP server and CQ prompt assets through homeManagerModules.dev-llm.

Repository layout

flake.nix                     # ledger outputs and ponygirls integration
nix/
  pkg/
    cq-ledgers/               # the Bun/TypeScript ledger workspace (run `bun` here)
      packages/{ledger,ledger-live,ledger-mcp,ledger-tui,ledger-web}
      package.json bun.lock tsconfig*.json …
      examples/sample-ledger/ # ready-made dataset
    cq-assets/                # ledger's contributed LLM assets (assets.nix, commands/, agents/)
    pi-extensions/            # CQ-specific Pi dispatch and status extensions
  lib/                        # CQ prompt and integration checks
docs/                         # operator documentation and historical research

ledger-suite

A ledger is an ordered set of milestones; each milestone holds typed items (tasks, defects, hypotheses, questions, decisions, goals, …). Everything is stored in an out-of-tree XDG SQLite primary, or accessed through a remote cq serve service. Optional Markdown backups are diffable and git-friendly. Milestones form a dependency DAG via their dependsOn / blockedBy references.

Packages

Package What it is
@cq/ledger The library: SQLite storage, private PostgreSQL service storage, Markdown backup codecs, schema/registry, FTS index, and MCP tool definitions.
@cq/ledger-mcp Standalone MCP server exposing the 68-tool management ledger surface over stdio or Streamable HTTP.
@cq/ledger-tui Ink terminal UI — a pure MCP client. Runs against a remote cq mcp --http (--mcp-url) or, by default, with the MCP server embedded in-process (--cwd).
@cq/ledger-web Browser explorer/editor + milestone DAG view — a pure MCP client served as a static bundle. Reverse-proxies to a remote cq mcp (--mcp-url) or, by default, embeds the MCP server in-process (--cwd).

The two frontends never read the ledger files directly — they always speak the MCP protocol. Embedded mode does not change that invariant: it merely co-locates the MCP server in the frontend's own process (an in-memory transport for the TUI; a co-hosted /mcp + /ws for the web server), so a single command needs no separately-running server.

Ordinary tool surface (45)

enumerate_ledgers, fetch_ledger, fetch_ledger_archive, fetch_item, update_item, create_item, create_ledger, search_items, fts_search, archive_milestone, archive_terminal_items, execute_finalize, list_milestone_items, snapshot, workset, derive_predicates, materialize_operator_action, acknowledge_operator_action, record_operator_action_evidence, revise_operator_action, complete_operator_action, reopen_item, unarchive_item, read_log, get_config, get_usage_stats, prepare_dispatch, fetch_dispatch_input, store_result, confirm_dispatch_completion, abort_dispatch, fetch_dispatch_result, start_dispatch, fetch_prompt, list_projects, mint_plan_claim_authority, claim_plan, publish_plan_draft, release_plan_claim, finalize_plan, worktree_manage, git_commit, git_resolve_continue, get_cohort_completion_status, get_cohort_status.

The seven attestation dispatch-lifecycle tools require both a supported durable backend (xdg, or PostgreSQL in its supported server construction) and an attested prompt surface. A server that cannot satisfy those prerequisites omits those seven names; broker availability similarly controls the two git dispatch-lifecycle tools. Omitting all nine leaves the canonical 34-tool ordinary non-dispatch surface instead of advertising handlers that can only fail.

The 68-tool management ledger surface uses a single breaking wire-response contract: item-bearing reads require an explicit compact/complement/full projection and eligible mutations return acknowledgements rather than full entities. See the @cq/ledger-mcp response matrix for every tool, retained field, pagination rule, and schema-checked example.

The persisted workset stores canonical roots and closes them over the active ownership, dependency, milestone, and plan graph. Management sessions may replace those roots; ordinary sessions may only get the configured graph or fetch a non-mutating preview. That closed graph bounds guarded mutations and external effects. UI visibility never expands workset authority. In the workset manager, ideas:I25 and goals:G159 remain visually excluded unless the configured roots close over them.

Anthropic SDK in-process hosts use createLedgerSdkMcpServer from @cq/ledger. It retains Zod handler validation while publishing the same compact tools/list definitions as stdio. createLedgerMcpTools remains the compatibility object factory for direct invocation and composition.

Quick start (Nix)

Embedded (one command, no separate server) — the frontend runs the MCP server in-process against a project's configured storage (XDG by default):

# Terminal UI, embedded:
nix run .#cq -- tui --cwd /abs/path/to/ledger-root

# Browser UI, embedded (serves a static bundle; open the printed URL):
nix run .#cq -- web --cwd /abs/path/to/ledger-root --port 5180

The embedded root resolves as --cwd > $LEDGER_ROOT > the process CWD.

Remote (shared server) — run one cq mcp --http and point the frontends at it (e.g. several UIs against one ledger, or a remote host):

# 1. Start the MCP server over HTTP against a ledger root.
nix run .#cq -- mcp --cwd /abs/path/to/ledger-root --http 7777

# 2a. Terminal UI:
nix run .#cq -- tui --mcp-url http://127.0.0.1:7777/mcp

# 2b. Browser UI:
nix run .#cq -- web --port 5180 --mcp-url http://127.0.0.1:7777/mcp

cq mcp also speaks stdio for clients that spawn it as a child (Claude Code, Codex, …): cq mcp --cwd /abs/path (no --http).

A ready-made dataset lives in nix/pkg/cq-ledgers/examples/sample-ledger — import its portable dump into an isolated XDG project before opening the UIs. See its README for the commands.

Server deployment (NixOS)

nixosModules.cq-server runs the cq serve multi-tenant hub against a native, tuned PostgreSQL on the same host (no containers). Minimal config:

imports = [ inputs.cq.nixosModules.cq-server ];
services.cq-server.enable = true;   # binds 127.0.0.1:5190, provisions local Postgres

Set host / port to change the bind, tokenFile for a bearer token (required for a non-loopback bind; injected via CQ_SERVE_TOKEN, not a ps-visible flag), an admin token for project-admin MCP, and postgres.tune.{totalMemoryMB,maxConnections,ssd} to size the database. Checkouts never select backend = "postgres"; they use backend = "remote" and CQ_LEDGER_REMOTE_TOKEN. See docs/drafts/20260819-2230-g81-remote-owner.md for the operator commands.

Storage layout

A checkout selects backend = "xdg" (default) or backend = "remote" in cq.toml. XDG primary state is keyed by project identity, not by checkout path:

$XDG_STATE_HOME/cq/projects/<projectKey>/
  ledger.db               # primary ledger state
  logs/                   # out-of-tree session/raw-log artifacts

When XDG_STATE_HOME is unset, the base is ~/.local/state. Backups default to none; in-tree exports a .cq/ Markdown dump and orphan-branch exports the same portable layout to the configured Git branch. cq restore imports a portable dump. Git plumbing remains supported for backups and managed Git effects; it is not a primary ledger backend. Remote checkouts use serverUrl and CQ_LEDGER_REMOTE_TOKEN; PostgreSQL stays private to cq serve.


LLM coding-agent harness

homeManagerModules.dev-llm composes the ponygirls Home Manager module with CQ's ledger package and prompt assets. The ponygirls module also works on its own, without CQ. The composed module sets up Claude Code, Codex, Pi, the platform yolo sandbox, and a shared programs.mcp registry (codegraph and ledger).

Any local-model (ollama) provider config is deliberately left to the consumer.

For a complete new-machine procedure, including prerequisites, activation, authentication, project initialization, hooks, skills, and the macOS Seatbelt sandbox, see Install the cq harness on a new Mac with Home Manager.

# flake.nix
inputs.cq.url = "github:7mind/cq";

# home-manager configuration
imports = [ inputs.cq.homeManagerModules.dev-llm ];
smind.hm.dev.llm.enable = true;

For the agents and sandbox without CQ, import inputs.ponygirls.homeManagerModules.dev-llm from github:7mind/ponygirls instead. Both modules use the same smind.hm.dev.llm option namespace.

Host/hardware facts the module cannot infer are surfaced as plain options the consumer wires from its own system config:

Option Purpose
smind.hm.dev.llm.yolo.promptExtensions Add tagged agent prompt fragments; works on Linux and macOS.
smind.hm.dev.llm.yolo.{extraReadOnlyPaths,extraReadWritePaths,extraDevicePaths} Linux bubblewrap binds and device passthrough.
smind.hm.dev.llm.yolo.{packages,sessionVariables,secretSessionVariables,hooks} Sandbox packages, environment, secret files, and pre-start hooks on Linux and macOS.
smind.hm.dev.llm.podman.{socketPath,socketUri} Linux rootless-Podman socket for container access.
smind.hm.dev.llm.llmSshKeyPath Linux SSH-key bind plus an agent prompt fragment.
smind.hm.dev.llm.pi.mcpDirectTools Expose selected MCP servers directly in Pi instead of only through its proxy.
smind.hm.dev.llm.{memorySections,assetBundles} Append memory text or asset bundles.
smind.hm.dev.llm.extraSkills Add user-defined skills (name → SKILL.md body) to every skill-aware agent; wins on name collision.

Other modules can append their own assetBundles (same shape as cq.llmAssets); the merged result is exposed read-only at smind.hm.dev.llm.merged.{skills,commands,agents,memoryText} for sibling modules to reuse.

The harness building blocks are exposed by ponygirls as individual packages — packages.<system>.{claude-code,codex,pi-coding-agent,llm-skills,llm-contexts} plus Linux yolo/reattach-llm or macOS yolo-darwin — so they can be built or consumed directly.

How you drive it (the cq flow)

The harness gives the agent a planning loop backed by the ledger, and exposes it through a tiny command surface — you mostly only ever type four things: /cq:plan, /cq:investigate, /cq:plan:follow-up, and /cq:advance. The agent does the rest; the ledger is where you and it meet.

A typical run:

  1. Stand up the sandbox. Launch through yolo (bubblewrap on Linux, Seatbelt on macOS) so the agent runs with project-scoped filesystem access and without per-action permission prompts.
  2. Install the assets. Bring in the MCP servers and the prompt/skill/command bundles — via the homeManagerModules.dev-llm module this is one import; that is what makes the /cq:* commands and the ledger MCP server available.
  3. Kick off the work. Start the agent and give it one of:
    • /cq:plan <task description> — start planning a new piece of work, or
    • /cq:investigate <defect description> — start root-causing a defect.
  4. Answer its questions. The agent stops and files clarifying questions into the ledger. Open a frontend (cq web or cq tui) and answer them there — your answers feed straight back into the plan.
  5. Refine the plan (optional, repeatable). Use /cq:plan:follow-up <goal id> <additional scope> to extend or adjust the plan, then answer the next round of questions. Repeat steps 4–5 until you are satisfied with the plan.
  6. Let it run. /cq:advance drives the whole flow — investigate → plan → implement — autonomously, pausing only when it needs something from you (an unanswered question or a user action). Re-run it after you unblock it.

Clipboard inside the Linux sandbox

Agent tools reach the host tmux clipboard through a per-launch host broker (yolo-clipboard-proxy, defects:D262) instead of a raw tmux socket bind. The broker grants exactly two fixed operations — set the host clipboard (tmux load-buffer -) and read it back (tmux save-buffer -) — over a dedicated 0600 socket inside a 0700 per-launch directory, while a PATH-prepended tmux shim inside the sandbox forwards only load-buffer/save-buffer/show-buffer and rejects every other tmux verb. The result is bounded clipboard read/write authority with no host tmux command authority: payloads are capped at 1 MiB, the sandbox TMUX coordinate names only the broker socket (never the host socket path or server PID), every bind that would expose the inherited socket is masked by the alias-resistant confinement pass, and every failure fails closed (clipboard disabled, never a raw host socket). Accepted fixed invocations can still trigger host-configured tmux hooks — after-load-buffer, after-save-buffer, and command-error — which belong to the host server's own configuration and receive no client-supplied argv; they are the only tmux side effects the bridge retains.

Project dispatch configuration

cq init writes cq.toml; cq.toml.example documents the complete schema. Model tokens use exactly one executable prefix: claude:<model>, codex:<model>, or pi:<provider>/<model>. In particular, pi:openai-codex/gpt-5.6-sol:xhigh remains a Pi provider route, while codex:gpt-5.6-sol:ultra selects the Codex executable. The packaged Codex vocabulary accepts low, medium, high, xhigh, max, and ultra.

[dispatch] has two global booleans. forceShellout defaults to false. unsafeDisableCodexReadOnlySandbox also defaults to false; when enabled, a Codex role that requested read-only instead runs with danger-full-access. This temporary compatibility switch removes Codex's OS sandbox, but does not widen the role's ledger tool profile. Both settings apply identically under the claude, codex, and pi active harnesses; [harness.*] blocks cannot override them.

Dispatch is CQ-driven. A parent calls start_dispatch with a role and its typed input; CQ resolves the role's token from cq.toml (or a configured panel token the parent names), and the token's harness is the dispatch's target harness, so cross-harness dispatch follows from configuration. CQ prepares against the target harness's prompt surface and launches the role through that harness's process boundary: claude -p with the role's attested built-in tools and its own profile-narrowed ledger server for Claude, the packaged cq-codex-role launcher for Codex, and pi -p for Pi (whose fenced result CQ stores). The parent never holds a capability; it reads the outcome with fetch_dispatch_result and a bounded waitMs, which returns the body exactly once. The resolved per-role token must name the target harness, so pi:openai-codex/... remains a Pi process/provider route rather than becoming a Codex route. A server cannot host a same-session native launch, so none is used.

Codex repository mutation remains brokered. implement-worker can receive only gitChangeCapability and use it only for git_commit, returning the durable gitReceipts chain. implement-conflict-resolver can receive only gitConflictCapability and use it only for git_resolve_continue, returning the durable conflictReceipts chain. Capabilities never enter argv, prompts, result bodies, or route metadata; the parent releases the managed worktree only after consuming and verifying the bound result.


Development (ledger workspace)

The Bun workspace lives under nix/pkg/cq-ledgers/:

nix develop                  # bun + node + toolchain (from repo root)
cd nix/pkg/cq-ledgers
bun install
bun test                     # full suite
bun run typecheck            # tsc -b
bun run lint                 # eslint
bun run check                # all three

Nix

packages.node-modules is a fixed-output derivation that fetches all npm dependencies. After changing dependencies (and bun.lock), refresh its outputHash in flake.nix: set it to sha256-AAAA… (52 As), run nix build .#node-modules, and paste the got: hash back.

Outputs:

  • packages.{cq,node-modules} + apps.{default,cq} (default is cq mcp).
  • homeManagerModules.dev-llm — ponygirls with CQ's ledger and prompts.
  • nixosModules.cq-server — runs cq serve over a native, tuned PostgreSQL.
  • llmAssets — the ledger's system-agnostic prompt/skill asset bundle.

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages