Local Self-Operation¶
This is the runtime contract for Heiwa on Devon's MacBook first. The same contract must scale to each enrolled user machine without changing the product model.
The goal is simple: the installed heiwa runtime should authenticate provider
CLIs through their owner-managed configs, read/write local state under
~/.heiwa, expose the cockpit on localhost, append durable JSONL evidence, and
derive local recall through Lance. Evidence sync to GitHub is planned but
disabled until a redaction and privacy boundary exists.
Required Local Inputs¶
| Input | Purpose |
|---|---|
~/.heiwa/config.toml |
Runtime configuration |
~/.heiwa/accounts.json |
Provider/account registry |
~/.heiwa/machine.json |
Local machine identity and capability manifest |
~/.heiwa/state/ |
Local runtime state, approvals, worker heartbeats |
~/.heiwa/evidence/ |
Canonical local JSONL evidence journal |
~/.claude/, ~/.codex/, ~/.gemini/ |
Provider-owned auth and hook posture |
Boot Contract¶
heiwa app start --port 7474 must:
- Serve the cockpit and local API on
127.0.0.1. - Report health at
/status/health. - Write local app worker heartbeats under
~/.heiwa/state. - Report provider, route, approval, worker, and hook posture without mutating provider-owned configs.
- Keep running without public DNS, GitHub connectivity, or evidence sync.
- Refresh
~/.heiwa/machine.jsonwith current host, OS, arch, install path, runtime version, and capability probes. - Adapt worker concurrency, polling cadence, and local-model use to machine load, battery, thermal state, and available runtimes.
- Surface pending update or restart requirements without interrupting active work.
- Require local runtime authentication for operator HTTP, turn submission,
cancellation, and
/ws/v1/operator; a localhost listener alone is not a trusted operator session.
Install and Update Authority¶
GitHub and Cloudflare form the public install source, but they do not have the same authority.
| Surface | Authority |
|---|---|
| GitHub repository | Canonical source code, tags, CI evidence, release artifacts, checksums, and install scripts |
| GitHub Releases | Canonical binary/archive distribution and version provenance |
| Cloudflare | Public edge, docs, install landing pages, update manifest cache, status, and future remote attach |
| Local machine | Installed binary, local config, provider auth, local state, and user-approved side effects |
Cloudflare may front or cache install/update material, but it must point back to GitHub release identity and checksums. Cloudflare must not become a second source of binary truth.
GitHub Releases are the authoritative public install and update path, including
on the operator MacBook. Local checkout promotion (heiwa app update --source
checkout) is reserved for development or recovery and must identify the exact
checkout commit in its receipt; it is not evidence of a public release.
heiwa app update --dry-run is the safe probe for the installed runtime and
defaults to GitHub Releases. It should report:
- installed version and path
- target version, channel, and release URL
- release commit or tag
- checksum/signature status when available
- whether restart is needed
- whether active tasks block restart
The runtime should prompt for update/restart when a newer compatible release is detected, when cockpit assets are newer than the running server, or when a schema/runtime boundary requires restart.
Restart and Update Contract¶
Restart is an operator-visible state transition, not a silent side effect.
Default behavior:
- Detect update or restart requirement.
- Classify active work as
none,pausable, orblocking. - Prompt the operator with target version, source, expected downtime, active tasks, and rollback path.
- Apply update/restart only after approval.
- Emit an evidence receipt with before/after versions and task handling.
Optional auto-restart is allowed only when explicitly enabled and one of these conditions holds:
- no active tasks, no pending approvals, no external side effects in flight
- all active tasks are paused, leased work is checkpointed, and traces/events are flushed
Auto-restart must not run while a provider subprocess, file mutation, network mutation, payment, booking, message send, or credential operation is in flight. Those cases require an approval prompt.
Pause-before-restart must:
- Stop accepting new work.
- Mark active tasks as paused with restart reason.
- Close or renew leases deterministically.
- Flush
~/.heiwa/state, traces, logs, and evidence receipts. - Restart the runtime.
- Rehydrate machine state and resume only tasks whose leases and approval policy still allow continuation.
Machine Initialization and Adaptation¶
Each machine initializes as a local Heiwa node with its own capabilities. Heiwa must assume N user machines over time, not one hardcoded owner path.
On first boot or install, the runtime should:
- Create or refresh
~/.heiwa/machine.json. - Record stable machine id, hostname, OS, arch, CPU/GPU class, memory, battery/thermal availability, install path, and runtime channel.
- Discover local providers and CLIs without mutating provider-owned configs.
- Discover local model runtimes such as Ollama.
- Record machine identity locally; future cross-machine sync must be explicitly redaction-gated.
- Write a boot receipt under local evidence state.
Adaptation rules:
- Battery or thermal pressure reduces background polling and pauses non-urgent work.
- Low memory or CPU load pressure reduces concurrency before degrading UX.
- Machines with strong local models should take cheap sovereign work first.
- Machines without local models should route through approved provider lanes.
- Machine-specific provider auth stays local and provider-owned.
- Cross-machine sync is planned through redacted evidence and machine identity; raw secrets never participate.
Agentic Runtime Workflow¶
Use this workflow when an AI agent is developing, testing, or operating Heiwa. The goal is to prove the current runtime, avoid stale localhost processes, and leave no temporary process or file behind.
1. Understand before acting¶
Read in this order before architecture or runtime changes:
HEIWA.mdfor canonical product truth.AGENTS.mdfor repo-specific agent rules.- This file for local boot, stop, and verification rules.
Classify the task as Intake, Execution, Evidence, or out-of-scope before editing. If the work does not advance one of those planes, defer it.
2. Probe without mutating¶
Start every runtime task with no-side-effect probes:
heiwa app update --dry-run
heiwa app runtime status --json
heiwa providers
When working from the checkout instead of the installed binary, prefer:
cargo run -q -p heiwa-shell --bin heiwa -- app runtime status --json
cargo run -q -p heiwa-shell --bin heiwa -- app update --source checkout --dry-run
Check the reported cli_path, state_dir, local_app.url, and
local_app.reachable. Also check update/restart hints when present. A reachable
app only proves that something is listening; it does not prove that the listener
is the code you just changed.
3. Avoid stale runtimes¶
Treat port 7474 as the installed product runtime. Do not assume it reflects
the current checkout after code edits.
For development verification, start a current checkout runtime on a temporary alternate port:
HEIWA_EVIDENCE_DIR=/private/tmp/heiwa-operator-e2e/evidence \
HEIWA_STATE_DIR=/private/tmp/heiwa-operator-e2e/state \
HEIWA_MACHINE_AUTH_TOKEN=operator-e2e-token \
cargo run -q -p heiwa-shell --bin heiwa -- app start --port 7475 --no-open
HEIWA_STATE_DIR relocates the app shell's worker heartbeat and the state path
reported by that shell; it does not relocate every Calendar, approvals, or
other module-specific read model. Together with HEIWA_EVIDENCE_DIR, it keeps
the operator-stream checks below out of installed 7474 state and the durable
operator corpus. Use a disposable HOME with a prebuilt binary when probing
broader state-backed APIs.
Then probe that same port:
curl -fsS http://127.0.0.1:7475/status/health
curl -fsS http://127.0.0.1:7475/api/v1/session
If a new API endpoint returns index.html, the request fell through to static
SPA serving. Assume you are probing the wrong runtime, an old runtime, or an
unimplemented route until proven otherwise.
Only run heiwa app update when the operator explicitly wants the installed
runtime changed. --dry-run is the default probe. Use
heiwa app update --source checkout only for developer reinstall from the
current checkout.
4. Verify the authenticated operator stream¶
Operator HTTP and WebSocket endpoints require local runtime auth. Native Desktop
uses signed local requests: HMAC v1 binds method, numeric local port, exact
request target, SHA-256 body digest, timestamp, and nonce. Runtime accepts at
most 30 seconds of clock skew and consumes every nonce once through its bounded
replay cache. Machine bearer auth remains compatibility-only; Desktop native
transport signs HTTP and WebSocket requests and never gives a bearer to the
renderer. An unset runtime auth configuration returns auth_not_configured; a
missing or invalid credential returns unauthorized. For the isolated checkout
runtime above, use the test bearer only against 127.0.0.1:7475:
curl -fsS \
-H 'Authorization: Bearer operator-e2e-token' \
-H 'Content-Type: application/json' \
-d '{"thread_id":"default"}' \
http://127.0.0.1:7475/api/v1/operator/threads
curl -fsS \
-H 'Authorization: Bearer operator-e2e-token' \
-H 'Content-Type: application/json' \
-d '{"client_request_id":"operator-e2e-1","prompt":"reply with ready","route_policy":{"mode":"auto"}}' \
http://127.0.0.1:7475/api/v1/operator/threads/default/turns
curl -fsS \
-H 'Authorization: Bearer operator-e2e-token' \
'http://127.0.0.1:7475/api/v1/operator/threads/default/events?limit=100'
The turn response returns turn_id, the stable post-user-message cursor, and
an encoded stream_url. The corresponding WebSocket request is:
GET ws://127.0.0.1:7475/ws/v1/operator?thread_id=default&after=<percent-encoded-cursor>
Authorization: Bearer operator-e2e-token
Use a WebSocket client that can set the compatibility Authorization header.
For Desktop verification, launch the native wrapper with HEIWA_APP_PORT=7475
and the same HEIWA_MACHINE_AUTH_TOKEN; its Tauri bridge signs the exact GET
target below the renderer for both HTTP and WebSocket. Verify initial replay reaches
caught_up, a newly appended shell event arrives without refresh, and reconnect
from the last durable cursor does not duplicate an event_id. Heartbeats and
assistant deltas are transient and never advance the durable cursor.
Browser preview is separate: heiwa app start --open puts a single-use,
60-second bootstrap token in the launch URL. The runtime consumes it once and
redirects with a port-scoped HttpOnly session cookie (eight-hour TTL). Browser
code receives neither bootstrap reuse authority nor machine bearer material.
Installed mode resolves canonical secrets from environment variables first, then from owner-private local files:
~/.heiwa/secrets/machine_auth_tokenforHEIWA_MACHINE_AUTH_TOKEN~/.heiwa/secrets/jwt_signing_secretforHEIWA_JWT_SIGNING_SECRET
Both files must be regular, non-symlink files with mode 0600 and contain one
ASCII token. Empty, oversized, multiline, group-readable, or world-readable
files are rejected. This keeps tokens out of LaunchAgent plists while giving
the installed CLI, runtime, and native Desktop one auth source.
Cursor and restart recovery are fail-closed:
- App startup exclusively leases the configured evidence root before recovery,
heartbeat, or API service. A second app process pointed at that same root
exits without mutating the operator stream; isolated verification roots may
run concurrently. The
.operator_runtime.locksidecar contains no identity, credential, or other payload. - Every mutating
OperatorSessionServiceholds a shared.operator_activity.locklease. Recovery requires exclusive activity ownership, so a live CLI, REPL, loop, or compatibility writer makes app startup fail before heartbeat/API service and prevents falseRUNTIME_RESTARTinterruption. Both lease sidecars remain zero-content. - HTTP replay returns structured
invalid_cursorfor unknown versions, stream fingerprint mismatches, offsets beyond EOF, or offsets not on an event boundary. The operator client must clear its disposable projection and replay the thread from the beginning. - The WebSocket sends an
invalid_cursorframe and closes so the client can perform that same bounded recovery; it must not guess a replacement offset. - On runtime restart, every nonterminal turn is durably closed with one
turn_interruptedevent whose reason isRUNTIME_RESTART. A turn with a pending operator cancellation closes asOPERATOR_CANCELLED. Open work is never silently resumed from process memory. - Readers skip unknown future operator-event schema versions, count them, and retain known events. Never rewrite or delete durable JSONL solely because a newer schema is present.
5. Start safely¶
Before starting a long-running runtime, decide:
- which port it owns
- whether it is installed-product verification or checkout verification
- what command will stop it
- what files, if any, will be created for probes
- whether restart/update prompts should be shown, deferred, or ignored for this verification
Prefer --no-open for agent verification so the browser is not disturbed.
6. Use the runtime¶
Use the local API and cockpit against the same port you started. Keep evidence local and concrete:
curl -fsS http://127.0.0.1:7475/status/health
curl -fsS http://127.0.0.1:7475/api/v1/runtime/snapshot
curl -fsS http://127.0.0.1:7475/api/v1/inbox
curl -fsS http://127.0.0.1:7475/api/v1/history
Do not fabricate cockpit rows. If the UI needs data, wire it to existing
~/.heiwa/state truth or add a clearly scoped read model with tests.
7. Stop what you started¶
Every agent-started runtime must be stopped before final reporting unless the operator explicitly asks to keep it running.
Preferred stop order:
- Send normal interrupt or SIGTERM to the exact process you started.
- Confirm the command prints its shutdown line or the port stops responding.
- Do not kill unrelated Heiwa processes on other ports unless the operator asked for that cleanup.
If sandbox policy blocks stopping a process, request escalation for the exact PID and explain that it is the temporary runtime started for verification.
8. Clean as you go¶
Clean up temporary verification artifacts before final reporting:
- temporary JSON probe files under
/private/tmp - ad hoc fixture directories created by tests
- one-off logs created only for the current verification
- temporary alternate-port runtime processes
Do not delete durable runtime truth under ~/.heiwa/state,
~/.heiwa/sessions, ~/.heiwa/logs, or evidence directories unless the
operator explicitly requests it.
Before final reporting, run:
git status --porcelain=v1 -uall
Report remaining dirty files honestly, separating agent changes from pre-existing or peer-agent changes.
Model Tier Matrix¶
| Lane | Preferred candidates when eligible | Other eligible candidates | Notes |
|---|---|---|---|
| Routine chat/status/audit | local Ollama where sufficient | OpenRouter, Codex, Claude Code | Cheapest candidate above the call's quality floor |
| Build/code | Codex CLI, Claude Code | Ollama coding model, OpenRouter | Provider CLIs own auth and quota semantics |
| Research/long context | Claude Code, Codex | OpenRouter | Route per call from live provider evidence |
| Review/strategy | Claude Code, Codex | OpenRouter | Use premium lanes only when the quality floor needs them |
| Sovereign work | local Ollama tiers | none | Local-only providers; fail closed when unavailable |
| Embeddings | ollama/qwen3-embedding:0.6b |
none | Requires a connected local Ollama runtime |
Gemini CLI is not a current fallback: the operator account returned
IneligibleTierError on 2026-07-19. Antigravity required authentication in the
same probe. Always refresh heiwa providers; entitlement, authentication, and
adapter discovery are separate facts.
Verification¶
heiwa app update --dry-run
heiwa app runtime status --json
heiwa providers
curl -fsS http://127.0.0.1:7474/status/health
The runtime is not ready for public access until the localhost checks pass and Cloudflare is explicitly re-enabled with fresh targets.