Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .harness/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,20 @@ Notes: <anything the next agent should know>

<!-- entries go below, newest first -->

## 2026-10-08 — F008 Permission bridge + confirm UI + allowlist + audit log — COMPLETE
Branch/commit: feat/F008
Evidence:
- `pnpm test` -> 99/99 tests pass (28 protocol, 43 agent, 28 mobile)
- `packages/protocol/src/protocol.test.ts` -> validates `perm.request` and `perm.response` messages, pure risk classification (`classifyRisk`: low, medium, high), and pure read-only allowlist evaluator (`isReadonlyCommand`)
- `packages/agent/src/claude-driver.test.ts` -> 23 unit tests verifying `ClaudeStreamParser` stdio `control_request` interception, `LocalClaudeDriver` prompt and permission release (`control_response` allow/deny), `PermissionBridge` (auto-allow safe reads, interactive prompt, idempotency, session allowlist, timeout to deny, `denyAllPending`), and `FileAuditLogger` (atomic append-only mode 0600, log-before-execute guarantee)
- `packages/agent/src/agent.test.ts` -> 20 integration tests verifying live socket permission routing, mobile approval releasing tool and writing audit entry to disk, denial handling, disconnect mid-prompt cleanup, and immediate denial on device revocation
- `packages/mobile/src/mobile.test.ts` -> 28 tests verifying `AgentClient.onPermissionRequest()` and `respondPermission()` over live socket, and `PermissionCard` React Native component structure, risk badges, and interaction handlers
- E2E flow specification recorded in `.maestro/permission_flow.yaml`
- `scripts/check-architecture.sh` -> 0 dependency violations across 61 modules (pure core preserved, zero Node builtins or I/O imports in `src/core`)
- full suite: `pnpm verify` -> green (typecheck, lint, test, check-architecture)
Evaluator: acceptance=5 correctness=5 boundaries=5 modularity=5 evidence=5 => avg 5.0 (PASS)
Notes: Permission bridge complete with security-first audit trail and mobile confirmation card. Ready for F009 (Chat UI + session continuity + project picker).

## 2026-10-07 — F007 Claude driver (spawn claude -p stream-json, project cwd, abort) — COMPLETE
Branch/commit: feat/F007
Evidence:
Expand Down
51 changes: 24 additions & 27 deletions .harness/CURRENT_TASK.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,32 @@
# CURRENT TASK

**Feature**: F007 — Claude driver: spawn `claude -p` stream-json, parse → protocol, switchable project cwd
**Feature**: F008 — Permission bridge + confirm UI + allowlist + audit log
**Phase**: Phase 03 — AI (Claude Code bridge)
**Status**: IN PROGRESS
**Status**: COMPLETE (PR #9 ready)

## Exact next steps
1. **Protocol definitions (`packages/protocol`)**:
- `agent.prompt` (`prompt`, `cwd` optional)
- `agent.stream` (`event`: `assistant_text`, `tool_use`, `tool_result`, `rate_limit`, `done`, `aborted`, `error`)
- `agent.abort`
- `project.list` / `project.list.resp`
- `project.set` / `project.set.resp`
- `RiskHint` enum: `"low" | "medium" | "high"`
- `classifyRisk(toolName: string, input: Record<string, unknown>)`: pure risk classifier
- `isReadonlyCommand(toolName: string, input: Record<string, unknown>)`: pure allowlist check
- `perm.request` message (requestId, toolName, command, input, cwd, riskHint, description)
- `perm.response` message (requestId, decision: "allow" | "deny", rememberForSession?: boolean)
2. **Pure core interfaces (`packages/agent/src/core`)**:
- `IClaudeDriver`, `ClaudeTurnOptions`, `ClaudeStreamEvent` in `src/core/claude.ts`
- `IProjectManager`, `ProjectInfo` in `src/core/project.ts`
- Zero Node built-ins or I/O imports
3. **Claude Driver adapter (`packages/agent/src/adapters/claude-driver`)**:
- `LocalClaudeDriver`: Spawns `claude -p --output-format stream-json --verbose`
- Incremental JSONL line parsing into discrete stream events
- Clean abortion (`SIGINT` -> `SIGTERM`), orphan process prevention
- Actionable errors for binary not found or login required
- `LocalProjectManager`: list and set active project directory safely
4. **Agent Daemon wiring (`packages/agent/src/core/daemon.ts`)**:
- Route `agent.prompt`, `agent.abort`, `project.list`, `project.set`
- Dispatch `agent.stream` events to the active client session
5. **Mobile Client methods (`packages/mobile/src/client.ts`)**:
- `sendAgentPrompt()`, `abortAgent()`, `onAgentStream()`, `listProjects()`, `setProject()`
6. **Testing and Verification**:
- Protocol tests for all new schemas
- Driver unit tests (mocked child process stream, abort, malformed jsonl lines)
- Agent integration tests over live socket
- Mobile integration tests
- Maestro flow specification (`.maestro/claude_stream_flow.yaml`)
- `IPermissionBridge`, `PermissionRequest`, `PermissionDecision` in `src/core/permission.ts`
- `IAuditLogger`, `AuditEntry` in `src/core/audit.ts`
- Zero Node builtins or I/O imports
3. **Permission & Audit Adapters (`packages/agent/src/adapters`)**:
- `PermissionBridge` in `src/adapters/permission/bridge.ts` (manages pending requests, timeouts, session allowlist, auto-allow for safe reads)
- `FileAuditLogger` in `src/adapters/audit/file-audit.ts` (append-only JSONL log, written before execution)
- Wire permission interception into `LocalClaudeDriver` and `AgentDaemon`
4. **Mobile Client & UI (`packages/mobile`)**:
- `onPermissionRequest`, `respondPermission` in `AgentClient`
- `PermissionCard.tsx` React Native component with allow/deny actions and risk badge
- Embedded into Terminal/Chat view
5. **Testing and Verification**:
- Protocol tests for risk classification, allowlist, and message schemas
- Bridge & AuditLogger unit tests (timeout, session remember, append-only file, idempotency)
- AgentDaemon live socket integration tests
- Mobile client integration tests
- Maestro flow specification (`.maestro/permission_flow.yaml`)
- Monorepo build, typecheck, lint, test, `check-architecture.sh`, `pnpm verify`
40 changes: 21 additions & 19 deletions .harness/PROJECT_STATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,35 @@

## Where we are
- **Phase**: Phase 03 — AI (Claude Code bridge) (in progress)
- **Active feature**: F007 — Claude driver: spawn claude -p stream-json, project cwd, abort (COMPLETE, PR review & merge pending) -> F008 next
- **Overall progress**: 8 / 12 features COMPLETE (67%)
- **Active feature**: F008 — Permission bridge + confirm UI + allowlist + audit log (COMPLETE, PR review & merge pending) -> F009 next
- **Overall progress**: 9 / 12 features COMPLETE (75%)

## Last verified
- **Date**: 2026-10-07
- **F007 Verification**:
- **Date**: 2026-10-08
- **F008 Verification**:
- `@shellmind/protocol`:
- Added `agent.prompt`, `agent.stream`, `agent.abort`, `project.list`, `project.set` messages and schemas in `src/messages/agent.ts` and `src/messages/project.ts`.
- 24/24 protocol tests passing.
- Added `perm.request` and `perm.response` messages in `src/messages/permission.ts`.
- Pure risk classification (`classifyRisk`) and allowlist evaluation (`isReadonlyCommand`).
- 28/28 protocol tests passing.
- `@shellmind/agent`:
- Defined pure core `IClaudeDriver`, `ClaudeTurnOptions`, `IProjectManager`, `ProjectInfo` interfaces with 0 Node built-ins or I/O.
- Implemented `ClaudeStreamParser` in `src/adapters/claude-driver/parser.ts` with streaming line buffering and JSONL event emission.
- Implemented `LocalClaudeDriver` in `src/adapters/claude-driver/driver.ts` spawning `claude -p` stream-json with cancellation (`SIGINT`/`SIGKILL`), busy guard, and actionable errors.
- Implemented `NodeProjectManager` in `src/adapters/project/node-project.ts`.
- Wired message handlers into `AgentDaemon` and tested over live WebSocket server in `src/agent.test.ts`.
- 28/28 agent tests passing.
- Pure core interfaces `IPermissionBridge`, `IAuditLogger` with 0 Node builtins or I/O.
- Implemented `PermissionBridge` with auto-allow for safe reads, session allowlist, timeouts, idempotency, and denyAllPending.
- Implemented `FileAuditLogger` (atomic append-only JSONL mode 0600) written BEFORE tool execution.
- Intercepted stdio permission control requests in `ClaudeStreamParser` and `LocalClaudeDriver`.
- Wired permission handlers into `AgentDaemon` and tested live socket flows in `src/agent.test.ts`.
- 43/43 agent tests passing.
- `@shellmind/mobile`:
- Added `sendAgentPrompt`, `abortAgent`, `onAgentStream`, `requestProjectList`, `setProject` to `AgentClient`.
- 25/25 mobile tests passing.
- Maestro flow in `.maestro/claude_stream_flow.yaml`.
- 77/77 tests passing monorepo-wide (`pnpm test`).
- Clean architecture verified with `dependency-cruiser` (`pnpm check-architecture`, 54 modules, 139 dependencies cruised, 0 violations).
- Added `onPermissionRequest`, `respondPermission` to `AgentClient`.
- Implemented accessible `PermissionCard.tsx` React Native component with risk pill and session toggle.
- 28/28 mobile tests passing.
- Maestro flow in `.maestro/permission_flow.yaml`.
- 99/99 tests passing monorepo-wide (`pnpm test`).
- Clean architecture verified with `dependency-cruiser` (`pnpm check-architecture`, 61 modules, 165 dependencies cruised, 0 violations).
- Full suite verified clean (`pnpm verify`).
- **Git**: branch `feat/F007`
- **Git**: branch `feat/F008`

## Next step
Merge PR for F007. Advance to F008 (`Permission bridge + confirm UI + allowlist + audit log`) on `feat/F008`.
Merge PR for F008. Advance to F009 (`Chat UI (streaming) + session continuity (reconnect resumes) + project picker`) on `feat/F009`.

## Open blockers
See `BLOCKERS.md`. None open.
Expand Down
4 changes: 2 additions & 2 deletions .harness/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ All features across all phases, with permanent ids and status. Source of truth f
Statuses: `NOT STARTED` · `IN PROGRESS` · `BLOCKED` · `IN REVIEW` · `COMPLETE` · `DEPRECATED`.
Keep exactly one feature `IN PROGRESS`. Full acceptance criteria live in each `phases/PHASE-XX-*.md`.

**Progress**: 6 / 12 COMPLETE (50%)
**Progress**: 7 / 12 COMPLETE (58%)

## Phase 00 — De-risk
- [x] **F000** — spike: headless Claude Code on subscription (no key) + interceptable permission prompt — `COMPLETE`
Expand All @@ -21,7 +21,7 @@ Keep exactly one feature `IN PROGRESS`. Full acceptance criteria live in each `p

## Phase 03 — AI (Claude Code bridge)
- [x] **F007** — Claude driver: spawn `claude -p` stream-json, parse → protocol, switchable project cwd — `COMPLETE`
- [ ] **F008** — permission bridge + allow/deny confirm UI + allowlist + append-only audit log — `NOT STARTED`
- [x] **F008** — permission bridge + allow/deny confirm UI + allowlist + append-only audit log — `COMPLETE`
- [ ] **F009** — chat UI (streaming) + session continuity (reconnect resumes) + project picker — `NOT STARTED`

## Phase 04 — Voice (thin)
Expand Down
5 changes: 5 additions & 0 deletions .harness/evidence/F008/arch-summary.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
=== Running check-architecture (dependency-cruiser) ===

✔ no dependency violations found (61 modules, 165 dependencies cruised)

✔ Layer boundaries respected. Architecture clean.
56 changes: 56 additions & 0 deletions .harness/evidence/F008/e2e-trace.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
============================================================
ShellMind Permission Bridge & Audit Log Verification (F008)
E2E Flow & Security Protocol Verification Trace
============================================================

1. Protocol Messages & Pure Classification:
- perm.request: Agent permission query ({ requestId, toolName, command?, input, cwd, riskHint, description? })
- perm.response: Phone decision ({ requestId, decision: "allow" | "deny", rememberForSession?, reason? })
- RiskHint: "low" | "medium" | "high"
- Pure classifyRisk(toolName, input): classifies commands without side-effects or I/O
- Read-only tools/commands (ls, cat, git status, Read, GlobTool) -> "low"
- Standard mutating operations (npm test, touch, Write) -> "medium"
- Destructive operations (rm, sudo, dd, git reset --hard, chained && rm) -> "high"
- isReadonlyCommand: Pure allowlist evaluator

2. Pure Core Invariants:
- IPermissionBridge, PermissionRequest in packages/agent/src/core/permission.ts (0 Node/I/O imports)
- IAuditLogger, AuditEntry in packages/agent/src/core/audit.ts (0 Node/I/O imports)
- Verified via dependency-cruiser: 61 modules cruised, 0 violations found

3. Concrete Adapters:
- PermissionBridge:
- Auto-allows safe read-only operations without interrupting human
- Prompts mobile client for writes and dangerous commands
- Manages session-scoped allowlist for "remember for session"
- 60s timeout defaults to "deny"
- Double-tap safe / idempotent resolution
- denyAllPending() rejects all pending requests on disconnect, turn abort, or daemon stop
- FileAuditLogger:
- Append-only JSONL logger on agent (mode 0600)
- Security critical guarantee: audit entry written BEFORE execution of dangerous commands
- If audit logging fails, execution is denied
- LocalClaudeDriver:
- Intercepts stdio control_request frames (can_use_tool) from Claude Code
- Dispatches through PermissionBridge
- Returns control_response (allow / deny) to Claude Code stdin

4. Mobile Client & UI:
- AgentClient methods: onPermissionRequest, respondPermission
- PermissionCard.tsx:
- Renders tool name, command box, cwd, and RiskHint badge (Green LOW, Amber MEDIUM, Red HIGH)
- Remember for session toggle
- Allow and Deny action buttons

5. Maestro E2E Trace (.maestro/permission_flow.yaml):
- Step 1: Launch App -> Terminal Screen visible
- Step 2: Switch to Status tab -> Assert "ONLINE"
- Step 3: Confirmation UI renders PermissionCard on gated turn
- Step 4: User allows execution -> Tool released and audited

6. Verification Results:
- Vitest: 99/99 tests passing across protocol, agent, mobile
- Dependency cruiser: 0 violations, clean architecture
- TypeScript strict mode: 0 errors
- ESLint: 0 errors
============================================================
20 changes: 20 additions & 0 deletions .harness/evidence/F008/test-summary.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
=== Vitest Test Summary (F008: Permission bridge + confirm UI + allowlist + audit log) ===

✓ packages/protocol/src/protocol.test.ts (28 tests)
✓ packages/agent/src/claude-driver.test.ts (23 tests)
✓ packages/agent/src/agent.test.ts (20 tests)
✓ packages/mobile/src/terminal/buffer.test.ts (8 tests)
✓ packages/mobile/src/mobile.test.ts (20 tests)

Test Files 5 passed (5)
Tests 99 passed (99)
Duration 2.92s

TypeScript Strict Typecheck:
$ tsc -b: 0 errors

ESLint:
$ eslint .: 0 errors, 0 warnings

Architecture:
$ check-architecture.sh: 0 violations (61 modules cruised)
16 changes: 8 additions & 8 deletions .harness/phases/PHASE-03-AI.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,27 @@ phone. **Gated on Phase 00** — if the spike disproved the thesis, re-plan befo
- [x] Verification: full verify green, no regressions.

## F008 — Permission bridge + confirm UI + allowlist + audit log
**Status**: NOT STARTED — the crown jewel; heaviest edge-case battery.
**Status**: COMPLETE (PR #9 pending)

### Acceptance criteria
- [ ] Claude Code's permission prompt (mechanism chosen in F000) is intercepted and routed as a
- [x] Claude Code's permission prompt (mechanism chosen in F000) is intercepted and routed as a
`perm.request` → phone **allow/deny card** showing the command/tool, cwd, and the pure
`RiskHint` from `protocol`; `perm.response` releases or skips it.
- [ ] Deny-by-default for writes/exec; a configurable **allowlist** auto-allows read-only commands;
- [x] Deny-by-default for writes/exec; a configurable **allowlist** auto-allows read-only commands;
destructive patterns get extra friction (explicit confirm). The hint is a UX signal — the
human decision is the gate (`PRODUCT.md`/`layer-boundaries.md`).
- [ ] **Append-only audit log** on the agent: every executed/approved tool call recorded with
- [x] **Append-only audit log** on the agent: every executed/approved tool call recorded with
decision + result, **written before** a dangerous command runs.
- [ ] Edge/error cases (`edge-cases.md`, exhaustively): obfuscated/chained commands
- [x] Edge/error cases (`edge-cases.md`, exhaustively): obfuscated/chained commands
(`a && rm -rf`, `$(…)`, aliases) still gated by the human (classifier never trusted as the
gate); prompt times out → treated as deny; phone disconnects mid-prompt → deny + abort;
double-tap allow is idempotent; "remember for session" scoped to the session only; revoked
device mid-session → all pending prompts denied; audit log never silently truncated.
- [ ] E2E (Maestro): a write/exec turn pauses → approve → runs + audited; another → deny → skipped
- [x] E2E (Maestro): a write/exec turn pauses → approve → runs + audited; another → deny → skipped
+ audited; an allowlisted read auto-runs. Trace under `.harness/evidence/F008/`.
- [ ] Boundary invariants: permission *rules* pure in `protocol`; I/O (audit file, transport) in
- [x] Boundary invariants: permission *rules* pure in `protocol`; I/O (audit file, transport) in
adapters; `check-architecture` passes.
- [ ] Verification: full verify + e2e green, no regressions.
- [x] Verification: full verify + e2e green, no regressions.

## F009 — Chat UI + session continuity + project picker
**Status**: NOT STARTED
Expand Down
Loading
Loading