A governed control plane for AI agents: local when private, cloud when needed, approval before action, receipts after every run.
Live console demo: cloud-routed tasks through the Hermes engine — route badges, step traces, session budget and spend tracking, and a running task that can be stopped mid-flight.
For the approval gate itself — a blocked write-capable tool call, a one-time operator allow, and the resulting receipt — see Tool approvals.
Most agent frameworks optimize for autonomy. TORQCLAW optimizes for trust: every agent runs behind a gateway that enforces what the operator decided, not what the model wants.
Local when private.
Cloud when needed.
Approval before action.
Budget before spend.
Receipts after every run.
Learning that is measurable, governed, and reversible.
TORQCLAW TrustOS is a TypeScript gateway, router, MCP bridge, and console UI wrapped around a forked Hermes Python execution engine.
- Approval before write. A write-capable tool never runs without operator approval — on both the local and cloud tiers. How approvals work
- Budget before spend. Cloud tasks carry an explicit budget; a breach cancels execution. Provider-reported spend is the enforcement source of truth. Cost control
- Receipts after every run. Terminal tasks produce queryable receipts from real telemetry — absent facts are distinguished from known facts, never invented. Receipts and replay
- Privacy beats routing confidence. Private and local-only tasks stay local, and the lock is visible in the route explanation — not silently overridden. Design invariants
[ Console / HTTP channel / future channel adapters ]
│
▼
┌─────────────────────────────────────────────┐
│ TypeScript Control Plane │
│ Fastify gateway :18790 · sessions · authz │
│ enrich → route → dispatch → receipts │
└───────────────┬─────────────────────────────┘
│
┌────────┴────────┐
▼ ▼
┌──────────────┐ ┌──────────────────────────┐
│ LOCAL_EDGE │ │ FRONTIER / Hermes Engine │
│ Ollama /v1 │ │ Python · MCP wrapper │
│ tool loop │ │ streamable-http │
└──────┬───────┘ └──────────┬───────────────┘
│ │
└──────────┬───────────┘
▼
┌─────────────────────────────────────────────┐
│ Universal MCP Bridge │
│ namespaced tools · capability policy │
│ path scope · approval-gated writes │
└─────────────────────────────────────────────┘
Requires Node.js ≥ 20.9, pnpm, uv, and Git.
git clone https://github.com/pilotwaffle/TORQCLAW.git
cd TORQCLAW
ops/install-torqclaw.cmd # Windows
# or: sh ops/install-torqclaw.sh
copy .env.example .env # Windows; use cp on POSIXThen start the stack:
pnpm doctor # preflight check
pnpm start # or ops/start-torqclaw.cmd / sh ops/start-torqclaw.shConsole: http://127.0.0.1:3000 · Gateway: 127.0.0.1:18790 · Engine health: 127.0.0.1:8000/health
The install wrappers run the submodule, frozen pnpm, contracts build, uv sync --locked, vendored Hermes editable install, and Hermes import checks. They never create or overwrite .env. Everything runs on loopback, and the engine defaults to stub mode — the stack comes up with zero API keys and zero cloud spend. Add a provider (HERMES_PROVIDER, HERMES_MODEL, HERMES_API_KEY) only when you want the FRONTIER tier. See Configuration.
Production rejects the deprecated shared gateway token. Bootstrap an operator credential once with node ops/bootstrap-operator.mjs; production probes read TORQCLAW_OPERATOR_CREDENTIAL or the generated operator-credential.token file.
| Area | Status |
|---|---|
| Phase 0 — Foundation Repair | Complete |
| Phase 1 — Visible Trust MVP | Complete |
| Phase 2 — Governed Learning MVP | Not started |
| Resilient extensibility (PRD-TCLAW-RESILIENT-EXTENSIBILITY-001) | Partially landed — see Resilient extensibility |
| Current master | faefb62, CI green |
Verified gate on e3ae332 |
991/991 TypeScript tests across 43 files · 186 passed / 1 skipped Python engine tests · typecheck 12/12 · contracts drift OK (8 schemas, 2 dirs) · build 7/7 |
Gate figures above were reproduced from a clean checkout of e3ae332, not copied from a pre-merge worktree.
The portable launcher derives every path from its own location; it does not require a particular drive, checkout name, or current working directory.
- Hybrid routing across LOCAL_EDGE and FRONTIER tiers.
- Privacy and local-only rules override model confidence.
- Role-based command authorization for operator/channel/node seats.
- Headless channels cannot silently approve gated actions.
- Gateway-owned grants: clients cannot inject
grantedTools. - All terminal task outcomes flow through the governed gateway event path.
- Every task binds to one named execution profile before dispatch; out-of-profile tools are never offered to the model.
- Optional provider failover retries retryable provider failures without replaying tool calls or side effects.
- Per-task budgets from console controls or
TORQCLAW_DEFAULT_MAX_COST. - Provider-reported spend is the enforcement source of truth.
- Budget breach cancels execution and emits a clear failure path.
- Honest fallback when spend is unavailable: the iteration cap is the guard.
- Cost summaries and receipt fields expose enforcement state without static pricing-table claims.
- Route preview and structured route explanation surfaces.
- Router diagnostics are surfaced to the console and receipts.
- Local/private safety locks are visible and not silently overridden.
- Route receipts show what was selected and why.
- Write-capable tools pause for approval on both tiers.
- Approval card v2 shows mechanical gate facts without inventing risk scores.
- Registry misses render honestly as
write-class (unclassified). - FRONTIER engine hooks render as engine approvals without fake capability labels.
- Approval history UI reads live approval truth from
tool_approvals, not stale receipt embeds. - Pending history rows are display-only; the live approval card remains the only action surface.
- Terminal tasks produce queryable receipts from real telemetry.
- Receipts avoid fabricated values and distinguish missing facts from known facts.
- Receipt replay and safe diagnostic export are separate surfaces: raw local diagnostics remain local/unredacted, while safe export uses server-side redaction.
GET_SAFE_EXPORTis an operator-only read command.- Safe export is generated on demand;
run_receipts.safe_export_jsondeliberately remainsNULL. - Unknown fields fail closed and do not export.
- Prompts, assembled context, raw event replay, raw args, raw results, and memory context are omitted wholesale.
- Retained short residue is scrubbed for known secret shapes before character caps.
- Absolute Windows, UNC, POSIX-home, and
~paths redact to[REDACTED:path]. - Approval status is read from live
tool_approvals, not frozen receipt embeds. - Safe export copy includes an explicit notice: known secret shapes were removed, but the export cannot guarantee that no secrets remain.
- Zod contracts remain the TypeScript source of truth.
- JSON Schema is emitted into both the contracts package and Python wrapper schema directory.
pnpm contracts:checkverifies generated schema drift.- CI gates TypeScript tests, typecheck, contracts drift, build, and Python wrapper tests.
docs/PRD-TCLAW-RESILIENT-EXTENSIBILITY-001.md scopes three slices. Their real
state on master differs per slice, and the distinction matters before relying
on any of them.
Deterministic provider chains with side-effect-safe retry. A task that fails on a retryable provider error can complete on a healthy fallback; failover never replays a tool call or an external side effect, and never switches providers after an irreversible side effect in the same task. Each attempt, transition reason, elapsed time, and cost provenance is recorded on the receipt.
Failover stays off unless TORQCLAW_PROVIDER_FAILOVER_ENABLED=true and
TORQCLAW_PROVIDER_CHAINS_PATH points at a valid chain file. Invalid
configuration fails closed with FAILOVER_CONFIG_REJECTED rather than silently
running unprotected. None of these variables are in .env.example; they are
deliberately explicit opt-in.
| Variable | Notes |
|---|---|
TORQCLAW_PROVIDER_FAILOVER_ENABLED |
Must be exactly true to enable |
TORQCLAW_PROVIDER_CHAINS_PATH |
Required when enabled; chain definition file |
TORQCLAW_PROVIDER_CHAIN_REVISION |
Chain revision stamp |
TORQCLAW_FAILOVER_DEFAULT_CHAIN / TORQCLAW_FAILOVER_CODING_CHAIN |
Chain selection by task class |
TORQCLAW_FAILOVER_ATTEMPT_TIMEOUT_MS / TORQCLAW_FAILOVER_TASK_DEADLINE_MS |
Per-attempt and whole-task bounds |
TORQCLAW_FAILOVER_TRANSITION_MIN_MS / TORQCLAW_FAILOVER_TRANSITION_MAX_MS |
Transition backoff bounds |
TORQCLAW_FAILOVER_CANCEL_ACK_MS |
Cancellation acknowledgement bound |
Every task resolves to exactly one named profile before dispatch, visible in route preview and on the receipt. A tool outside the active profile is never sent to the model and cannot execute through the bridge. Requesting a broader profile than the session default requires operator authority; requesting a stricter one does not. Unknown or unauthorized broadening fails closed.
| Profile | Capabilities | Tiers | Path / network | Approval required |
|---|---|---|---|---|
read_only |
read | LOCAL_EDGE | none / none | — |
workspace_write |
read, write | LOCAL_EDGE, FRONTIER | workspace / none | write |
browser_research |
read | LOCAL_EDGE, FRONTIER | none / browser | — |
terminal_power |
read, write, exec | LOCAL_EDGE, FRONTIER | configured / configured | write, exec |
Default profile by task type: DATA_EXTRACTION and SUMMARIZATION →
read_only; ROUTINE_AUTOMATION → workspace_write; AUTONOMOUS_RESEARCH →
browser_research; COMPLEX_CODING → terminal_power.
engines/hermes_kernel/mcp_wrapper/verified_skill_store.py implements atomic
staging, digest-bound approval, activation, rollback, and journal recovery. As
of GS-COORD it is reachable at runtime: the live
skill_queue.decide() → governed_skills.install_approved_skill() path drives
it through ActivationCoordinator, under
LOCK → quiescence → publish → invalidate → commit → verify → unlock with
restore-before-unlock. Activation is transactional — on failure the prior
projection is restored, the new digest is not active, the approval is not
falsely consumed, and no retained journal can later complete it silently.
As of GS-ROLLBACK, rollback is also end-to-end: the
rollback_skill MCP tool → governed_skills.rollback_governed_skill() path
runs the same coordinator transaction, re-publishing the target version's
bytes and verifying their digest — never governance alone (the GS-ACCEPT F-1
divergence).
As of GS-DISABLE, disable is end-to-end too: the disable_skill MCP tool →
governed_skills.disable_governed_skill() path runs the same coordinator
transaction with the projection step reversed — it retains and removes the
published projection, invalidates the prompt cache, commits
store.disable(), then verifies the skill is both governed-disabled and
no longer published. The store-only disable() had the identical
governance/projection divergence F-1 found in rollback(): it reported
"off" while the model kept receiving the skill in every rendered system
prompt. Installed digest history survives a disable, and rollback is the
designed inverse — re-enabling means rolling back to the exact digest you
want, so there is deliberately no separate enable surface that would have to
guess one. Empty and whitespace-only skill bodies are now refused at the
package-validation seam (MIN_SKILL_BYTES), closing GS-ACCEPT finding F-2.
Using governed skills (operator flow): set TORQCLAW_GOVERNED_SKILLS=1
(this deployment already has it in the user environment). A skill reaches the
queue by operator paste or an agent draft (queue_skill); the console
approval card drives APPROVE_SKILL, which runs the full governed install
and now reports the kernel's real outcome — a busy engine or a
failed/unproven activation surfaces as an explicit ERROR event with retry
guidance, never as a silent success. Rollback, disable, and version listing exist
today as MCP tools only (rollback_skill, disable_skill,
list_skill_versions on the engine server) — there is no console button
for them yet. Disable un-publishes and turns governance off together;
re-enabling is rollback_skill to the digest you want back.
Operator ruling 2026-08-11: governed skills are ON for this deployment
(TORQCLAW_GOVERNED_SKILLS=1 in the operator's user environment). The
prerequisite evidence existed: GS-ACCEPT booted a real agent against the
shipped binary (receipt: 8 passed / 2 xfailed at 83690f3), its blocking
finding was closed by GS-ROLLBACK, and the acceptance suite re-ran green on
the merged tree. The operator collapsed the separate soak window into live
operation — governed mode IS the soak, monitored in use, with flag-off as
the immediate rollback. The flag itself still defaults off in code: a fresh
deployment must still opt in explicitly.
Skills reach the queue by operator paste and digest-bound review, OR — behind
TORQCLAW_REMOTE_SKILL_SOURCES (default off) — by a signed remote fetch
(install_remote_skill). The kernel (engines/hermes_kernel/mcp_wrapper/ skill_trust.py) fetches over bounded HTTPS (no redirects, connect/read
timeouts, limit+1 streaming), independently computes the package digest
from the fetched bytes, and verifies an Ed25519 signature over that digest
against an origin-scoped, operator-configured trust root with signed
revocation bundles — colocated with the install authority, so the process
that installs is the process that verifies. On the local (non-remote) path,
skill.json still accepts optional Ed25519 signature metadata for shape
validation only; no cryptographic verification runs there and signatures
are not required.
The former packages/gateway/src/skillTrust.ts (Ed25519 origin trust
bundles, 661 lines, zero production importers) was deleted rather than
wired: two implementations of canonical JSON is a signature-forgery seam
waiting for a divergence, so its model — not its lines — was ported into
the Python trust engine above. ops/reachability.mjs's DORMANT map and
pnpm reachability record the retirement; tests/reachability.test.ts
pins that the file never reappears.
Two further caveats recorded with the checkpoint: Phase-1 failover evidence rests on a deterministic loopback/fake-provider fixture rather than a live two-provider pilot, and canonical signing uses a bounded deterministic JSON canonicalizer without RFC 8785 interoperability vectors.
Graphify project profile files are present on master through governed Graphify PRs and are accepted current repository state. Graphify relocation or cleanup remains a separate operator-lane item and is not part of TrustOS Phase 1.
| Path | What |
|---|---|
packages/contracts |
Zod source of truth; emits JSON Schema for TypeScript and Python consumers |
packages/router |
Hybrid route rule hierarchy and diagnostics |
packages/gateway |
Fastify gateway, sessions, authz, dispatch, receipts, approvals, safe export, profile resolution, provider failover |
packages/inference |
LOCAL_EDGE Ollama-compatible tool loop |
packages/bridge |
MCP server registry, namespacing, tool filtering, capability/path/profile policy |
packages/channel-http |
HTTP channel adapter using the role: 'channel' seat |
apps/console |
Next.js console: route preview, receipts, approvals, safe export UI, /api/health |
engines/hermes_kernel |
Python MCP wrapper over vendored hermes-agent; attempt ledger, failover runtime, verified skill store |
ops/ |
Portable install/start wrappers, doctor, readiness, e2e and live-acceptance harnesses |
docs/TRUSTOS-BUILD-LEDGER.md |
Implementation ledger and phase closeout record |
docs/PRD-TCLAW-RESILIENT-EXTENSIBILITY-001.md |
Failover / profiles / verified-skills program spec |
| Variable | Default | Notes |
|---|---|---|
TORQCLAW_DATA_DIR |
~/.torqclaw |
Gateway state DB, credentials, skill queue |
TORQCLAW_PORT / TORQCLAW_HOST |
18790 / 127.0.0.1 |
Loopback-first gateway binding |
TORQCLAW_CONSOLE_PORT / HERMES_BIND_HOST |
3000 / 127.0.0.1 |
Portable console and engine ports/hosts |
TORQCLAW_OPERATOR_CREDENTIAL |
generated credential file | Optional override for production operator probes; the shared gateway token is forbidden in production |
HERMES_ENGINE_URL / HERMES_ENGINE_TOKEN |
http://127.0.0.1:8000/mcp |
Python engine MCP endpoint; local URLs cannot carry credentials |
OLLAMA_HOST / TORQCLAW_LOCAL_MODEL |
localhost:11434 / torq-local |
LOCAL_EDGE model config |
HERMES_MODEL / HERMES_PROVIDER / HERMES_API_KEY / HERMES_BASE_URL |
unset stub mode | FRONTIER provider config |
HERMES_CODING_PROVIDER / HERMES_CODING_MODEL / HERMES_CODING_API_KEY / HERMES_CODING_BASE_URL |
optional | Per-task override for complex coding tasks |
TORQCLAW_PREFER_CLOUD |
unset | 1 lowers the bar for cloud routing while privacy/local-only still win |
TORQCLAW_DEFAULT_MAX_COST |
unset/unlimited | Fallback budget when a task sets none |
HERMES_MAX_ITERATIONS |
30 |
Hard cap on the Hermes loop |
HERMES_STUB_COST_USD |
0.0 |
Stub-mode spend value for tests |
HERMES_STUB_COST_UNAVAILABLE |
unset | 1 makes stub spend unavailable |
The console controls are user-owned and per submission:
- Budget — default/env fallback, free local-only, fixed amounts, or custom
maxCostUsd. - Mode — Auto, This machine only (
LOCAL_ONLY), or Cloud allowed. - Private — sets
containsSensitiveData; automation must not clear it. - Fast/urgent — latency hint for routing.
- Stop — cancels a running task through the gateway.
A credential-looking prompt may trigger a client-side suggestion to mark private. It never silently flips the flag and never blocks submission.
A write-capable tool never runs without operator approval.
- LOCAL_EDGE raises
ToolApprovalRequiredbefore executing an ungranted gated tool. - FRONTIER blocks through the Hermes
pre_tool_callhook and returns through the same gateway approval path. APPROVE_TOOLcarries onlyapprovalIdand decision; the gateway reads the tool and args from its own database.- Allow once re-mints a gateway-owned one-shot grant.
- Deny ends with a terminal error and does not store memory.
- Approval history is read-only and display-only; history rows cannot approve.
Safe export is designed for support/debugging without pretending to solve all data-leak risk.
- Request via
GET_SAFE_EXPORTfrom an operator seat. - Export is generated on demand from allowed receipt/task/approval facts.
- Server redaction removes known secret shapes and absolute path shapes.
- The UI displays the redaction report before copy.
- Copy JSON uses the server SafeExport object exactly.
- Copy Markdown is a pure projection of that object with GitHub-paste escaping.
- Raw local diagnostics remain available only as explicitly labeled local/unredacted diagnostics.
The console is the primary operator client. packages/channel-http is the first non-console adapter and connects as role: 'channel'.
TORQCLAW_HTTP_CHANNEL=1 node --env-file=.env ops/dev-up.mjs
curl -s localhost:18792/task -H 'content-type: application/json' \
-d '{"prompt":"research MCP gateway namespacing and compare the options"}'A task that needs interactive approval returns a pending-approval response honestly; a headless channel cannot click the approval card.
Copy ops/servers.example.json to ~/.torqclaw/servers.json.
Each server entry supports:
idfor namespace prefixing, such asfilesystem__read_file.stdioorstreamable-httptransport.- optional
toolsallowlist to keep large servers focused. - capability/approval policy.
pathArgKeysand path scopes for read/write/deny enforcement.
Path-like arguments are resolved before policy matching. deny always wins.
Run the current gate:
pnpm typecheck
pnpm test
pnpm contracts:check
pnpm build
cd engines/hermes_kernel
uv run pytestCurrent gate, reproduced from a clean checkout of e3ae332:
991/991 TypeScript tests across 43 files
186 passed / 1 skipped Python engine tests
typecheck 12/12
contracts drift OK — 8 schemas in 2 checked-in dirs
build 7/7
The Python figure is CI's gate: uv run pytest from engines/hermes_kernel.
The tests/resilience/ suite at the repository root is a separate
manifest-driven harness and is not part of that count.
On a cold checkout the tests/failover/* cases spawn real engine subprocesses
and can exceed the 15s per-test timeout while the Python environment is still
being resolved. This presents as roughly a dozen failing files on a first run
and clears on a warm re-run. Let uv sync finish before treating a failover
timeout as a real regression.
Historical Phase-1 closeout gate, for reference only — 805/805 TypeScript and
75/75 Python tests at commit f5fbee7.
For a real provider acceptance run, configure non-placeholder matching gateway tokens plus HERMES_MODEL, HERMES_PROVIDER, and HERMES_API_KEY, start the stack, then run:
node --env-file=.env ops/doctor.mjs --runtime --production
pnpm acceptance:liveLive acceptance is deliberately not part of public CI and never succeeds by skipping, stubbing, or accepting a pending/error result. Public CI uses a synthetic-token, stub-mode production-launch e2e instead.
- No hidden authority. Client requests cannot inject grants, scopes, approvals, or internal authorization.
- Privacy beats routing confidence. Private/local-only tasks stay local.
- Budget before spend. Cloud tasks carry an explicit budget story.
- Approval before write. Write-class tools pause on both tiers.
- Receipts from evidence. Receipts and exports are built from recorded facts; absent facts are not invented.
- Safe export is honest. It removes known secret shapes but never claims total safety.
- Protocol drift fails fast. Generated schemas are checked against source of truth.
- Wrap, do not rewrite Hermes. Upstream Hermes remains vendored; TORQCLAW owns
mcp_wrapper/. - Governed phases. Phase 2 is not started until explicitly scoped and approved.
Completed:
- Phase 0 — Foundation Repair.
- Phase 1 — Visible Trust MVP.
- Portable production runtime, doctor/readiness gating, and live-provider acceptance harness.
TCLAW-FIX-G— resolved 2026-08-01: decision-time cache refresh plus authoritative live-approval overlay inGET_RECEIPT.TCLAW-FIX-H— resolved 2026-08-01: shared bounded diagnostic redaction boundary plus versioned legacy-row migration/quarantine.
In progress:
- Resilient extensibility — provider failover and execution profiles landed; the local verified-skill lifecycle (install, activation, rollback, disable) is integrated end to end and ON for this deployment (see "Verified skills" above). Signed remote skill sources are landed behind
TORQCLAW_REMOTE_SKILL_SOURCES(default off). Remaining from that PRD: console surfaces for rollback, disable, and version listing (MCP tools only today), plus the recorded caveats — a live two-provider failover pilot and RFC 8785 interoperability vectors for canonical signing.
Not started:
- Phase 2 — Governed Learning MVP.
Filed non-blocking residuals:
TCLAW-GRAPHIFY-CLEANUP— Graphify cleanup/relocation operator lane.
Apache-2.0 — see LICENSE. The vendored Hermes engine (engines/hermes_kernel/vendor/hermes-agent) is MIT, Copyright (c) 2025 Nous Research; its upstream license is retained in place. See NOTICE.
