Skip to content
Open
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
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ jobs:
# codebase targets.
zig:
runs-on: ubuntu-latest
env:
# Integration tests are deterministic/offline; hosted MCP is covered separately.
GRAFF_NO_SMOLIFY: "1"
steps:
- uses: actions/checkout@v4

Expand All @@ -54,9 +57,6 @@ jobs:
- name: Live JSON stream contains no raw stdout lines
run: python3 scripts/test-json-live.py zig-out/bin/graff

- name: PTY spinner anti-stealth test
run: python3 scripts/test-pty-spinner.py zig-out/bin/graff

- name: PTY REPL interaction test
run: python3 scripts/test-pty-repl.py zig-out/bin/graff

Expand Down
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,36 @@ turns it back on, and `/goal status` shows the objective and its current state.
blocked, cancelled, or exhausted) once the work is done, you step in, or a safety
limit is hit, instead of pausing for confirmation between routine steps.

### MCP servers

Graff speaks both MCP transports directly: local stdio servers and remote
Streamable HTTP servers. Smolify (`https://app.smol.ly/mcp`) is connected as a
core, anonymous documentation service; it needs no Node bridge or project
configuration. This performs discovery requests at startup and tool queries may
be sent to the hosted service; set `GRAFF_NO_SMOLIFY=1` for offline or
privacy-sensitive sessions. Other servers can be added from the shell or during
a session:

```sh
graff mcp add context7 -- npx -y @upstash/context7-mcp
graff mcp add mobbin --url https://api.mobbin.com/mcp
graff mcp login mobbin # OAuth discovery + browser PKCE flow
graff mcp login smolify # optional access to authenticated Smolify tools
# In the REPL: /mcp add mobbin --url https://api.mobbin.com/mcp
```

The equivalent `.mcp.json` URL entry is
`{"mcpServers":{"mobbin":{"url":"https://api.mobbin.com/mcp"}}}`. Remote
responses may use either `application/json` or `text/event-stream`; Graff keeps
`Mcp-Session-Id` state and sends `MCP-Protocol-Version` on requests.
For OAuth-protected endpoints, `graff mcp login <name>` performs protected
resource and authorization-server discovery, dynamic client registration, and
a browser PKCE flow. Tokens are stored outside the repository under
`~/.simple-harness-mcp` with user-only permissions and refreshed automatically.
Static HTTP headers can alternatively be added with
`--header 'Authorization=Bearer TOKEN'` (they are stored in `.mcp.json`, so
prefer a restricted token and do not commit that file).

The line editor supports ↑/↓ history (persisted to `~/.simple-harness-history`),
Tab completion (commands, and model names after `/model `), and emacs-style
editing (Ctrl-A/E/W/U/K, Option+Delete, word moves). The selected model is
Expand Down
14 changes: 6 additions & 8 deletions docs/debugging-the-harness.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

How we chase down "why is graff slow / wrong here" bugs, distilled from real sessions
(most recently #117, the first-turn latency hunt that found *three* stacked synchronous
calls, and the 💩-spinner hunt that exposed non-representative testing).
calls).

## The one core lesson
Almost every "graff feels slow" bug is the **main thread blocking on a network or model
Expand Down Expand Up @@ -98,14 +98,12 @@ Find the `.await(io)` / join on the critical path. Real ones found this way:

## 6. Verify like you mean it
- **Mutation-test the guard.** Reintroduce the bug and confirm the *exact* test reddens.
A green suite that doesn't fail when you break the code proves nothing — that blind spot
is how the runtime-built 💩 spinner survived `strings`/`grep` for hours.
- **Representative > surface.** Scan rendered bytes from a real PTY, hit a real-socket
mock — not `strings`, not a frame-fn called in isolation (which can't see a
startup-gated override).
A green suite that doesn't fail when you break the code proves nothing.
- **Representative > surface.** Exercise rendered output through a real PTY and use a
real-socket mock rather than testing only isolated helpers.
- Let `ci.yml` gate it: `zig build`, `zig fmt --check`, `zig build test`, the JSON
live-control test, the **PTY anti-stealth scan**, and **SDK-drift regen** (CI was red for
the whole history once because a model/tool landed without regenerating `sdk/`).
live-control test, and **SDK-drift regen** (CI was red for the whole history once
because a model/tool landed without regenerating `sdk/`).

## Traps that cost real time
- **Prompt caching neutralizes tool-list size.** With ~99% cached input (`9216/9289 in`),
Expand Down
Loading
Loading