2026-10-25 05:04:11 +01:00
# cap (taicpp)
Port of the CAP section of `../tai.py` (`CAP_VERSION` ... `TAI_CAP_MANIFEST` ),
normative text in `../cap.md` . Namespace `detz::cap` , sources in `src/cap/` ,
one class per `.h` /`.cpp` pair. The C++ names are the Python names in
camelCase; behavior is verified by running both programs (see Verification).
2026-10-27 19:03:32 +01:00
**Wire parsing is untrusted input** : every byte here comes off a socket, so the parsers follow [cpp-safety.md ](cpp-safety.md ) (overflow-safe size checks, unsigned range-checked lengths, guarded shifts, no exception escaping the read loop, hostile-input tests under sanitizers). We do not accept regressions in that.
2026-10-25 05:04:11 +01:00
## Spec delta (this milestone)
- Real `TAI_CAP_MANIFEST` replaces the one-line placeholder
(`CapAgentManifest::TAI_CAP_MANIFEST` , `--cap-manifest` prints it plus
the `print()` newline; byte-identical to `tai.py --cap-manifest` ).
- All Cap classes ported: events, errors, bindings, manifest, registry,
session config, stream-json, speak session, the four drivers, answerer,
session, fleet, CLI. The old `Orchestrator` grant/check placeholder is gone.
- Layer `wire_*` (namespace `detz::wire` ) supplies what Python's stdlib gave
tai.py: `Json` (json), `WireToml` (tomllib), `WireRegex` (re), `WireProc` /
`WirePty` (subprocess, PtyProc), `WireHttp` (urllib, http.client, http.server),
`WireArgParse` (argparse), `WireShlex` , `WireDifflib` , `WireHash` , `WireText` ,
`WireOs` .
## Parity table (Python -> C++)
| Python | C++ |
|---|---|
| `CAP_VERSION` `CAP_MANIFEST_SCHEMA` `CAP_PROFILE_CODING` `CAP_MANIFEST_REVISION` `CAP_PROBE_TIMEOUT` `CAP_ERROR_CODES` `CAP_ERROR_STRINGS` `CAP_SESSION_CONFIG_ENV` `CAP_SPEAK_MAX_TURNS` `CAP_SPEAK_DIFF_MAX` `CAP_PTY_SETTLE_MS` `CAP_PTY_IDLE_MS` `CAP_PTY_SUBMIT_GAP_MS` `CAP_PTY_RESUBMITS_MAX` `CAP_PTY_SCROLLBACK` `CAP_PTY_INIT_TIMEOUT` `CAP_STREAM_LINE_MAX` `CAP_STREAM_STDERR_KEEP` `CAP_SESSION_POLL` `CAP_TURN_TIMEOUT` `CAP_WORKTREE_DIR` `CAP_ROUTE_QUEUE_MAX` `CAP_FLEET_DIFF_MAX` `CAP_MENTION_RE` `CAP_ACP_VERSION` `CAP_ACP_TERMINALS_MAX` `CAP_ACP_TERM_BUF` `CAP_ACP_TERM_WAIT_MAX` `CAP_ACP_FS_MAX` `CAP_A2A_TIMEOUT` `CAP_ANSWER_TIMEOUT` `CAP_ANSWER_PARALLEL` `CAP_ANSWER_MARKER` `CAP_ANSWER_RISKS` | `cap_constants.h` (same names) |
| `CAP_ERROR_SYMBOLS` | `capErrorNumeric()` in `cap_error.h` |
| `TAI_CAP_MANIFEST` | `CapAgentManifest::TAI_CAP_MANIFEST()` |
| `CapError` | `cap_error.h` |
| `CapEvent` | `CapEvent` (`KINDS` , `DIRECTIONS` , `REQUIRED` , `ENUMS` , `make` , `validate` , `direction` ) |
| `CapBinding` | `CapBinding` (`ORDER` , `UNSUPPORTED` , `declared` , `select` ) |
| `CapManifest` | `CapManifest` |
| `CapRegistry` | `CapRegistry` |
| `CapSessionConfig` | `CapSessionConfig` |
| `CapStreamJson` | `CapStreamJson` |
| `CapSpeakSession` , `cap_interrupt` , `cap_speak_main` | `CapSpeakSession` , `CapInterrupt` , `CapSpeakMain` |
| `CapDriver` | `CapDriver` (`CapDriver::create` in `cap_driver_factory.cpp` ) |
| `CapPtyDriver` | `CapPtyDriver` over `WirePty` and `CapVtScreen` (port of `TuiVtScreen` , `CapScreen` seam) |
| `CapPipeReader` , `cap_proc_kill` , `cap_proc_reap` , `cap_stderr_drain` | `CapPipeReader` , `CapProcUtil` , `CapStderrDrain` |
| `CapStreamDriver` `CapAcpDriver` `CapA2aDriver` | same names |
| `CapAnswerer` | `CapAnswerer` |
| `CapTurnResult` `CapSession` `CapFleet` | same names |
| `cap_cli_main` `cap_cli_help` `cap_resolve_main` `cap_chat_main` `cap_run_main` `cap_fleet_plan` `cap_print_result` `cap_build_answerer` `cap_answer_flags` | `CapCli` static methods |
## Event kinds
`cap.session.ready` , `cap.text_chunk` , `cap.tool_call.start` ,
`cap.tool_call.delta` , `cap.tool_call.end` , `cap.plan` , `cap.thought` ,
`cap.ask_user` , `cap.permission.request` , `cap.usage` , `cap.error` ,
`cap.artifact` , `cap.fs.change` , `cap.pty.raw_bytes` ,
`cap.user_input.inject` , `cap.cancel` , `cap.session.config` ,
`cap.ask_user.answer` , `cap.permission.response` .
## Errors
Symbols: `cap_manifest_missing` , `cap_session_config_missing` ,
`cap_unsupported_capability` , `cap_budget_exceeded` , `cap_invalid_answer` ,
`cap_unknown_permission` , `cap_queued_input_unsupported` ,
`cap_cancel_unsupported` , `cap_binding_unavailable` ,
`cap_profile_unsupported` , `cap_scope_violation` , `cap_path_not_found` ,
`cap_io_error` , `cap_terminal_unavailable` , `cap_terminal_killed` .
String codes: `rate_limit` , `auth_error` , `tool_timeout` , `context_overflow` ,
`model_unavailable` , `pty_died` , `parse_failed` , `git_dirty` , `test_failed` ,
`merge_conflict` , `language_server_down` .
## Seams (host-provided)
`CapAgentPort` / `CapSpeakHost` (the agent for `--cap-speak` ), `WireLog`
(debug log sink), `WireApp::setVersion` (VERSION on the wire),
`CapPtyDriver::setScreenFactory` (swap the VT screen). Details and the exact
hooks: `docs/wiring/capmcp.md` .
## Differences from Python (all declared)
- `CapAnswerer` runs `[binary, --auto, prompt]` directly; Python ran
`[sys.executable, tai.py, ...]` . Default binary is `/proc/self/exe` .
- `CapVtScreen` parses SGR but does not store colors/attributes (text-only
consumer) and keeps no scrollback history.
- Regex: ECMAScript engine with Python syntax translation. Python-only syntax
beyond named groups, `\A` , `\Z` , `$` , bare `{` /`}` , leading `(?i)` is not
translated; compile error texts differ from `re.error` .
- argparse help is plain (no 3.14 color).
- Dates in TOML come back as strings.
- Terminal `terminal/output` keeps the `read(65536)` blocking-chunk behavior.
- Signals: SIGINT/SIGTERM set a flag polled by waits (`CapInterrupt` ).
2026-10-25 19:16:18 +01:00
## Agents, models and `@agent` mentions
2026-10-25 18:01:34 +01:00
2026-10-25 19:16:18 +01:00
taicpp lists the installed CAP agents, discovers their models (manifest `[models]` list, optional
`--cap-models` probe), and lets a message start with `@agent` , `@agent:model` or `@model` , matched fuzzily and
run in a supervised panel on the multiplexer screen. Everything about it is in
[cap-agents.md ](cap-agents.md ); the matching in [fuzzy.md ](fuzzy.md ); the panels, supervision and result
collection in [orchestration.md ](orchestration.md ). CAP itself (events, bindings, manifest, fleet) is
unchanged by this and stays specified on this page.
2026-10-25 18:01:34 +01:00
2026-10-25 05:04:11 +01:00
## Verification
`tests/capmcp_diff.py` (JSON, TOML, str(), float repr, regex vs CPython),
`tests/capmcp_cli_diff.py` (`--cap-manifest` , `--cap resolve|chat|run` incl.
stream-json, PTY, ACP and A2A fake agents, argparse errors at four widths vs
`tai.py` ), `tests/capmcp_unit.cpp` (tables and drift check).