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
42 changes: 42 additions & 0 deletions docs/SURFACE.md
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,48 @@ flows resume [--json] [--no-spawn] [--data-dir <dir>] <run-id>
flows observer [--data-dir <dir>]
```

### Agent sidechannel (initial byte-stream slice)

Local agent workers (`flows run --local-agent`) open
`<data-dir>/runs/<run-id>/steps/<step-id>/pty.sock` for the raw Claude/Codex
adapters and print `PTY <path>` on stderr. SDK workers opt in with `dataDir`
and can receive the path through `onPtyReady`. Run and step IDs come from the
kernel dispatch, including for authored `f.agent` calls.

A subscriber sends `HELLO view\n`, `HELLO drive\n`, or
`HELLO passthrough\n`, then receives live stdout/stderr bytes. View and
passthrough are passive. Only drive forwards subsequent bytes to child stdin.
In this pipe-based slice, a drive greeting must arrive within 100ms of child
startup. Without one, the worker closes stdin so unattended and passive-view
agents receive EOF. Later drive greetings are rejected without marking human
intervention; a closed stdin pipe cannot be reopened. Supporting drive attachment
at arbitrary times requires a future terminal/session transport. Drive readers
pause while child stdin writes flush, preserving input under backpressure.
There is no backlog, terminal resize, or framing after the greeting. Socket
access is restricted to the worker's OS user. Slow, malformed, excess, and
broken subscribers are disconnected independently; absent subscribers or an
unavailable socket do not fail a step or change its lease/deadline handling.

Operator input stays off journal. Influenced output follows the usual worker
output decoding and completion path. Any accepted drive greeting marks
`step.completed.human_intervention: true`, even without input. Passive and
unattached completions omit the field. The marker persists on failed attempts
as well, and marked completions are excluded from cross-run memoization.

`flows resume` refuses marked runs with exit 2 and
`REFUSED [human_influenced_run] step "<id>"` before recovery, unless passed
`--allow-human-influenced`. The same flag permits `flows replay` to cross a
marked completion; replay may already have printed earlier entries when it
refuses. `--at` can still inspect a prefix before that boundary. The flag is
per invocation and does not clear the journal marker.

**Follow-up scope:** this minimal slice forwards the existing process pipes;
it does not yet allocate an actual terminal. True PTY/resize support,
wrapper-session attachment, crash-safe intervention recording before a worker
completion, and the companion `agent-relay attach --external-pty` client are
follow-ups. Long UNIX socket paths and stale socket files disable this optional
channel; they do not prevent agent execution.

`flows observer` prints a single `https://agentrelay.com/observer?key=<ot_live_...>`
URL to stdout using the same mint used by `flows run`. It is daemon-free: no
socket is opened, no `relayflowd` binary is invoked, the data dir is not
Expand Down
72 changes: 72 additions & 0 deletions docs/evidence/spec-Q/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Slice Q verification

## PR #338 Bugbot follow-up

Rebased onto `origin/main` at `494f2a11`. Unattended, passive, and incomplete
subscribers now allow stdin EOF after a 100ms startup drive-attachment window.
Late drive greetings are rejected without setting the intervention marker.
Drive input pauses its socket until each child write completes, including
writes that exceed the pipe's buffer capacity. Arbitrary-time drive attachment
remains a terminal/session transport follow-up, documented in SURFACE.md.

After SDK `npm ci --ignore-scripts` and repository-root
`npm install ./packages/surface --prefix packages/sdk --no-save --ignore-scripts`,
ran from `packages/sdk`:
`npm run typecheck && ./node_modules/.bin/vitest run tests/worker-cli.test.ts tests/pty-sidechannel.test.ts`.
Exit 0; literal command and output: [bugbot-fixes.txt](bugbot-fixes.txt).
This is focused SDK regression evidence, not a new live-provider acceptance run.

## Original slice evidence

This is a minimal byte-stream proof for #334, with completion markers and
resume/replay protection. Actual PTY allocation, wrapper-session attachment,
crash-safe intervention recording before completion, and the companion
agent-relay external-pty client remain follow-ups (see SURFACE.md §5).

Run/step IDs already arrive in AgentWorker's kernel dispatch; no redundant
identity plumbing was added to authored-worker-step.ts. This tree has no
separate resume.ts: resume lives in cli/run.ts and argument parsing in cli.ts.

All commands ran in this worktree on 2026-09-11. Each linked file is captured
command output. Exit statuses below refer to the completed tool processes.

## SDK

From packages/sdk:

- `npm run typecheck` — exit 0, [output](typecheck.txt).
- `npm run typecheck:tests` — exit 0, [output](typecheck-tests.txt).
- `npm run build` — exit 0, [output](build.txt).
- `npx vitest run tests/pty-sidechannel.test.ts tests/worker-cli.test.ts tests/worker-cli-abort.test.ts tests/cli-replay.test.ts`
— exit 0, 57 passed, [output](sdk-focused.txt).
- `npx vitest run tests/cli.test.ts -t 'human-influenced resume'`
— exit 0, 1 passed / 63 excluded by filter, [output](resume-cli.txt).
- `RELAYFLOWD_BIN=/Users/khaliqgant/.relayflows-toolchain/target/3923540030/debug/relayflowd npx vitest run`
— exit 1, [initial output](sdk-initial.txt). Bun was absent from PATH,
the live Claude analyzer was unavailable, and one live-kernel test timed out.
- `PATH=/Users/khaliqgant/.bun/bin:$PATH RELAYFLOWS_ALLOW_ANALYZER_SKIP=1 RELAYFLOWD_BIN=/Users/khaliqgant/.relayflows-toolchain/target/3923540030/debug/relayflowd npx vitest run`
— exit 0, 1215 passed / 4 skipped, [final output](sdk-final.txt).
This is not gate-2/live-analyzer acceptance evidence. The analyzer skip is
explicit; the initial unskipped failure is retained above.

Dependencies: SDK `npm ci --ignore-scripts`, then root
`npm install ./packages/surface --prefix packages/sdk --no-save --ignore-scripts`.
The local surface needed a build; its pre-existing lockfile was out of sync,
so it was installed with `npm install --ignore-scripts --package-lock=false`
and built with `npm run build`. No dependency manifests/locks changed.

## Rust

From the repository root unless otherwise noted:

- `PATH=/Users/khaliqgant/.cargo/bin:$PATH ops/cargo.sh test --manifest-path kernel/Cargo.toml --workspace`
— exit 0, [output](rust-workspace.txt), including the new durable marker,
refusal, unchanged-journal-on-refusal, and explicit-override test.
- From kernel: `PATH=/Users/khaliqgant/.cargo/bin:$PATH ../ops/cargo.sh build --locked --release -p relayflowd`
— exit 0, [output](rust-release.txt).
- `PATH=/Users/khaliqgant/.cargo/bin:$PATH ops/cargo.sh test --manifest-path kernel/Cargo.toml -p relayflowd-core --test memoization`
— exit 0, [output](rust-memoization.txt). This final focused run includes
the added assertion excluding human-influenced completions from reuse.

The initial cargo invocation lacked rustc on PATH; the commands above use the
existing toolchain. `git diff --check` also exited 0.
36 changes: 36 additions & 0 deletions docs/evidence/spec-Q/bugbot-fixes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
$ cd packages/sdk
$ npm run typecheck && ./node_modules/.bin/vitest run tests/worker-cli.test.ts tests/pty-sidechannel.test.ts

> @relayflows/sdk@2.0.8 typecheck
> tsc --noEmit && tsc -p tsconfig.type-tests.json


RUN v2.1.9 /Users/khaliqgant/flows-spec-Q-sidechannel/packages/sdk

✓ tests/pty-sidechannel.test.ts (11 tests) 5016ms
✓ view attach preserves worker completion and marks only drive 1048ms
✓ passthrough attach preserves worker completion and marks only drive 800ms
✓ none attach preserves worker completion and marks only drive 707ms
✓ none subscriber lets an unattended CLI read EOF 311ms
✓ rejects drive after EOF without marking human intervention 678ms
✓ delivers all drive bytes in order across child stdin backpressure 661ms
✓ tests/worker-cli.test.ts (13 tests) 24222ms
✓ custom wrapper execution identity > passes an explicit safe environment at identification and execution 381ms
✓ custom wrapper execution identity > refuses a wrapper symlink retarget before delivering private values 520ms
✓ custom wrapper execution identity > bounds wrapper execution after acknowledgement 360ms
✓ custom wrapper execution identity > refuses a duplicate execute protocol frame 400ms
✓ custom wrapper execution bounds are reader-owned > resolves when a conforming wrapper leaks a stdio pipe to a background helper 1864ms
✓ custom wrapper execution bounds are reader-owned > resolves when the leaked helper inherits stderr only 2009ms
✓ custom wrapper execution bounds are reader-owned > resolves when a wrapper leaks a stdio pipe and exits before identifying 3280ms
✓ custom wrapper execution bounds are reader-owned > journals a completionReason at the default bound when a wrapper leaks a stdio pipe 11264ms
✓ custom wrapper execution bounds are reader-owned > accepts an execute token and an over-8KiB payload flushed in one write 1289ms
✓ custom wrapper execution bounds are reader-owned > accepts the same over-8KiB payload whether or not it coalesces with the execute token 896ms
✓ custom wrapper execution bounds are reader-owned > still bounds an un-terminated handshake buffer and names the bound 377ms
✓ delivers the journaled memory pack to the real wrapper and excludes its charge from completion usage 1297ms

Test Files 2 passed (2)
Tests 24 passed (24)
Start at 21:10:32
Duration 24.48s (transform 50ms, setup 0ms, collect 81ms, tests 29.24s, environment 0ms, prepare 75ms)

Exit status: 0
4 changes: 4 additions & 0 deletions docs/evidence/spec-Q/build.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

> @relayflows/sdk@2.0.8 build
> tsc && node scripts/make-cli-executable.mjs

10 changes: 10 additions & 0 deletions docs/evidence/spec-Q/resume-cli.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

RUN v2.1.9 /Users/khaliqgant/flows-spec-Q-sidechannel/packages/sdk

✓ tests/cli.test.ts (64 tests | 63 skipped) 8ms

Test Files 1 passed (1)
Tests 1 passed | 63 skipped (64)
Start at 20:32:05
Duration 1.18s (transform 450ms, setup 0ms, collect 792ms, tests 8ms, environment 0ms, prepare 71ms)

38 changes: 38 additions & 0 deletions docs/evidence/spec-Q/rust-memoization.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
Compiling syn v3.0.4
Compiling zerovec-derive v0.11.6
Compiling displaydoc v0.2.7
Compiling serde_derive v1.0.229
Compiling ref-cast-impl v1.0.27
Compiling thiserror-impl v2.0.20
Compiling ref-cast v1.0.27
Compiling zerovec v0.11.8
Compiling zerotrie v0.2.5
Compiling thiserror v2.0.20
Compiling serde v1.0.229
Compiling tinystr v0.8.4
Compiling potential_utf v0.1.6
Compiling icu_collections v2.3.0
Compiling icu_locale_core v2.3.0
Compiling icu_provider v2.3.1
Compiling ahash v0.8.12
Compiling fluent-uri v0.3.2
Compiling email_address v0.2.9
Compiling ulid v1.2.1
Compiling icu_normalizer v2.3.0
Compiling icu_properties v2.3.0
Compiling referencing v0.33.0
Compiling idna_adapter v1.2.2
Compiling idna v1.1.0
Compiling jsonschema v0.33.0
Compiling relayflowd-core v0.1.0 (/Users/khaliqgant/flows-spec-Q-sidechannel/kernel/relayflowd-core)
Finished `test` profile [unoptimized + debuginfo] target(s) in 7.60s
Running tests/memoization.rs (/Users/khaliqgant/.relayflows-toolchain/target/3923540030/debug/deps/memoization-3560adb32830fb1c)

running 4 tests
test distinct_large_kernel_integers_do_not_alias_through_float_rounding ... ok
test match_reuses_output_with_provenance_and_zero_cost_without_dispatch ... ok
test changed_spec_or_input_dispatches_and_legacy_or_failed_records_miss ... ok
test canonical_corpus_agrees_with_typescript_and_key_permutations ... ok

test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

127 changes: 127 additions & 0 deletions docs/evidence/spec-Q/rust-release.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
Compiling proc-macro2 v1.0.107
Compiling unicode-ident v1.0.24
Compiling quote v1.0.47
Compiling libc v0.2.189
Compiling stable_deref_trait v1.2.1
Compiling version_check v0.9.5
Compiling autocfg v1.5.1
Compiling cfg-if v1.0.4
Compiling serde_core v1.0.229
Compiling getrandom v0.3.4
Compiling zerocopy v0.8.56
Compiling smallvec v1.15.2
Compiling serde v1.0.229
Compiling litemap v0.8.3
Compiling num-traits v0.2.19
Compiling memchr v2.8.3
Compiling writeable v0.6.4
Compiling generic-array v0.14.7
Compiling utf8_iter v1.0.4
Compiling icu_normalizer_data v2.3.0
Compiling icu_properties_data v2.3.0
Compiling parking_lot_core v0.9.12
Compiling syn v3.0.4
Compiling syn v2.0.119
Compiling typenum v1.20.1
Compiling zmij v1.0.23
Compiling ref-cast v1.0.27
Compiling synstructure v0.13.2
Compiling zerofrom-derive v0.1.7
Compiling yoke-derive v0.8.2
Compiling num-integer v0.1.47
Compiling zerofrom v0.1.8
Compiling num-bigint v0.4.8
Compiling aho-corasick v1.1.5
Compiling ahash v0.8.12
Compiling zerovec-derive v0.11.6
Compiling displaydoc v0.2.7
Compiling serde_derive v1.0.229
Compiling ref-cast-impl v1.0.27
Compiling serde_json v1.0.151
Compiling scopeguard v1.2.0
Compiling find-msvc-tools v0.1.11
Compiling shlex v2.0.1
Compiling regex-syntax v0.8.11
Compiling num-rational v0.4.2
Compiling cc v1.4.4
Compiling lock_api v0.4.14
Compiling ppv-lite86 v0.2.21
Compiling yoke v0.8.3
Compiling num-iter v0.1.46
Compiling num-complex v0.4.6
Compiling rand_core v0.9.5
Compiling pkg-config v0.3.34
Compiling once_cell v1.21.4
Compiling regex-automata v0.4.18
Compiling bit-vec v0.8.0
Compiling borrow-or-share v0.2.4
Compiling vcpkg v0.2.15
Compiling itoa v1.0.18
Compiling bit-set v0.8.0
Compiling num v0.4.3
Compiling rand_chacha v0.9.0
Compiling parking_lot v0.12.5
Compiling libsqlite3-sys v0.35.0
Compiling crypto-common v0.1.7
Compiling block-buffer v0.10.4
Compiling percent-encoding v2.3.2
Compiling zerovec v0.11.8
Compiling zerotrie v0.2.5
Compiling uuid v1.26.0
Compiling fluent-uri v0.3.2
Compiling vsimd v0.8.0
Compiling foldhash v0.1.5
Compiling thiserror v2.0.20
Compiling outref v0.5.2
Compiling lazy_static v1.5.0
Compiling utf8parse v0.2.2
Compiling fraction v0.15.4
Compiling anstyle-parse v1.0.0
Compiling uuid-simd v0.8.0
Compiling referencing v0.33.0
Compiling tinystr v0.8.4
Compiling potential_utf v0.1.6
Compiling icu_locale_core v2.3.0
Compiling icu_collections v2.3.0
Compiling hashbrown v0.15.5
Compiling email_address v0.2.9
Compiling digest v0.10.7
Compiling fancy-regex v0.16.2
Compiling regex v1.13.1
Compiling rand v0.9.5
Compiling thiserror-impl v2.0.20
Compiling cpufeatures v0.2.17
Compiling is_terminal_polyfill v1.70.2
Compiling colorchoice v1.0.5
Compiling icu_provider v2.3.1
Compiling icu_normalizer v2.3.0
Compiling icu_properties v2.3.0
Compiling num-cmp v0.1.0
Compiling base64 v0.22.1
Compiling anstyle v1.0.14
Compiling bytecount v0.6.9
Compiling anstyle-query v1.1.5
Compiling anstream v1.0.0
Compiling ulid v1.2.1
Compiling idna_adapter v1.2.2
Compiling sha2 v0.10.9
Compiling idna v1.1.0
Compiling jsonschema v0.33.0
Compiling hashlink v0.10.0
Compiling fallible-iterator v0.3.0
Compiling bitflags v2.13.1
Compiling clap_lex v1.1.0
Compiling fallible-streaming-iterator v0.1.9
Compiling ryu-js v1.0.3
Compiling anyhow v1.0.104
Compiling strsim v0.11.1
Compiling heck v0.5.0
Compiling clap_builder v4.6.6
Compiling clap_derive v4.6.4
Compiling wait-timeout v0.2.1
Compiling relayflowd-core v0.1.0 (/Users/khaliqgant/flows-spec-Q-sidechannel/kernel/relayflowd-core)
Compiling clap v4.6.6
Compiling rusqlite v0.37.0
Compiling relayflowd-journal v0.1.0 (/Users/khaliqgant/flows-spec-Q-sidechannel/kernel/relayflowd-journal)
Compiling relayflowd v0.1.0 (/Users/khaliqgant/flows-spec-Q-sidechannel/kernel/relayflowd)
Finished `release` profile [optimized] target(s) in 34.01s
Loading
Loading