Metadata-Version: 2.4
Name: sid-harness
Version: 0.3.0
Summary: SID first-party local coding harness (CLI/TUI) — drives the SID native loop against SID's OpenAI-compatible /v1.
License: Proprietary
Project-URL: Homepage, https://superintelligencedog.com
Project-URL: Documentation, https://superintelligencedog.com/docs
Project-URL: Source, https://superintelligencedog.com
Keywords: sid,coding-agent,cli,harness
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Operating System :: OS Independent
Classifier: Environment :: Console
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Provides-Extra: publish
Requires-Dist: build>=1.2; extra == "publish"
Requires-Dist: twine>=6.0; extra == "publish"
Requires-Dist: sigstore>=3.0; extra == "publish"

# sid-harness — SID first-party local coding client (v1)

A small CLI/TUI client that runs a coding task through **SID's own native
loop** against SID's OpenAI-compatible `/v1`. Running a model on your desktop no
longer requires a third-party coding harness: SID *is* the harness.

- **One engine.** The loop, its four-tool contract, and its path denylist are
  the gateway's `app/native_agent.py`, vendored **verbatim** into the package as
  `sid_harness/_native.py` — one loop, mirrored, and kept byte-identical by a
  parity test. Never reimplemented.
- **One backend.** SID routes, meters, and caps every call under **your** key.
  No aggregator, no other provider SDK.
- **One command.**

```bash
sid setup                              # verify your key via /v1/me, save it, pick a dir
sid run --task "Fix the off-by-one in add()." --dir ./my-project
```

Output: the workspace selection, the model + diff, the final response, and a
**run receipt** written to `<dir>/.sid/runs/<run_id>.json` (override with
`--receipt`). The CLI prints the receipt as a `file://` link.

## Install / run

No third-party dependencies (stdlib only), and no monorepo checkout — the
package is self-contained. Either:

```bash
pipx run --spec infra/sid-harness sid run --task "..." --dir ./proj   # install + run
pipx install infra/sid-harness          # or install the `sid` console script
pip install infra/sid-harness           # plain pip works too
# or run straight from the tree:
python -m sid_harness run --task "..." --dir ./proj
```

The loop ships in the package, so nothing under `infra/sid-gateway` is needed at
runtime. The one optional seam that does use the gateway is `--context`
(repo-scale retrieval over `app.rag`); it is discovered when a gateway checkout
is present and overridable with `SID_HARNESS_GATEWAY_PATH`. Every other command
works with no checkout.

## First run

`sid setup` verifies the key against `GET /v1/me`, then writes
`~/.sid/config.json` (owner-only) with the key, base URL, and your default
project directory. Later commands read that file when the env var or flag is
absent, so `sid run --task "..."` works with no `export` and no `--dir`.
Override the location with `SID_CONFIG_PATH`.

```bash
sid setup --dir ./my-project            # non-interactive: key from SID_API_KEY
sid setup --api-key "<your-key>" --dir .  # or pass it explicitly
```

Maintainers publish the signed wheel with `scripts/publish_sid_harness.sh`
(Sigstore attestations via `twine upload --attestations`). Public install
commands are wired into the landing/docs pages only after the PyPI probe
returns 200; the commands above remain the source-tree install until then.

## Commands

```bash
sid run --task "<goal>" --dir <path> [--model auto] [--verify] [--write] [--json]
sid run ... --git-write [--git-branch NAME] [--git-message MSG] [--no-pr]  # opt-in branch/commit/PR (SUB-95)
sid run ... --context [--context-k N]  # prepend repo-scale retrieved context (SUB-55)
sid run ... --mcp "<server cmd>"       # expose an MCP server's tools (SUB-56, repeatable)
sid run ... --bounds-config <file>     # override loop bounds (SUB-58)
sid run ... --test-cmd "python -m pytest -q"   # run the approved tests locally (SUB-80)
sid tui  --dir <path>                  # interactive terminal loop, same engine
sid status --dir <path> [--diff]       # local git/worktree status (read-only)
sid session start|resume|replay        # durable local sessions (SUB-58)
sid tools [--mcp "<server cmd>"] [--json]   # list the loop's tool contract
sid policy --dir <path> [--json]       # show the platform worktree/gate policy
sid lsp [--dir <path>]                 # LSP: compiler diagnostics -> loop (SUB-96)
sid apply --dir <path> --receipt <p> [--approve]   # apply an approved run receipt
sid editor install [--target-dir <p>] [--force]    # one-command VS Code install
sid selftest [--receipt <path>]        # one loop turn against a local stub endpoint
```

Common options: `--base-url` (env `SID_BASE_URL`, default
`https://superintelligencedog.com/v1`), `--api-key` (env `SID_API_KEY`),
`--routing-profile` (default `agent`), `--criteria` / `--out-of-scope`
(repeatable), `--max-tokens`, `--reasoning-effort`, `--receipt`, `--quiet`.

`--verify` reviews the produced diff through the gateway's existing
`POST /v1/verify/patch` — the harness does not carry a second verify path.

`--write` applies the loop's changed files to the **real working tree**
(SUB-54). It is off by default (read-only). Deletions are never applied. Inside
the platform repo, a source write from the MAIN checkout is refused by the repo
policy (SUB-57), which delegates to the platform's own Gate 31.

`--git-write` is the explicit opt-in that finishes the coder loop (SUB-95):
create a branch (`--git-branch`, default `sid/<run_id>`), commit **only** the
files that `--write` applied, push that branch, and open a pull request with
`gh` (`--git-base`, `--no-pr` to skip). Each step asks for its own approval;
`--approve` pre-approves the steps for non-interactive use, and without a
terminal or `--approve` every step fails closed. The path hard-refuses
`main`/`master` (including sub-refs), never force-pushes, and the receipt's
`git_write` block names the branch, commit SHA, and PR URL. Without
`--git-write` the harness remains read-only and never commits or pushes.

`--test-cmd` is the human-approved test command (SUB-80). The CLI splits it into
an **argv list** and executes it with `subprocess` in the `--dir` root —
never through a shell. The runner must be allowlisted (`python -m pytest`,
`pytest`, `python -m unittest`, `npm test`, `yarn/pnpm test`, `cargo test`,
`go test`), argv may not point outside the workspace, and the run is bounded
(timeout + output capture). The receipt records `tests_executed`, the test
backend, exit code, and pass/fail. Nothing is committed or pushed.

## What v1 is (and is not)

**Is:** a bounded workspace loaded from `--dir`, the existing native loop, SID as
the only model backend, and a written run receipt. As of SUB-54 the workspace is
a **local driver**: real file read/write (`--write`), real `git` **status/diff**
(read-only — `sid status`), worktree awareness (linked worktree vs main
checkout), and a `.gitignore` filter layered on the shared `native_agent._safe_path`
secret/VCS/dependency denylist. The receipt records the git block and the files
written.

**Also wired (SUB-55/56/57/58):** repo-scale **context** (`--context` indexes the
whole tree and prepends sanitized, data-boundaried retrieval — reuses the
gateway's `app.rag`), the **tool ecosystem** (`sid_harness.tools`: a registry
over the one loop, an MCP stdio/HTTP client, a skills loader, a plan/todo gate,
subagent fan-out — reachable via `sid run --mcp` and `sid tools`), **durable
sessions** (`sid session`), configurable **bounds** (`--bounds-config`), and
**repo policy** (a write from the platform MAIN checkout is refused).

**Tests (SUB-80):** with `--test-cmd`, the loop's `run_approved_tests` tool and
the final verification step execute the approved argv locally against the
workspace root; the receipt records backend/exit/passed and
`tests_executed: true`. Without an approved command the receipt stays
`tests_executed: false` — never a claim. By default the harness **never commits
and never pushes**; only the explicit `--git-write` opt-in branches, commits,
pushes a feature branch, and opens a PR (SUB-95), and it never touches
main/master.

## Localhost bridge (for the web Studio)

The web Studio runs in a browser and cannot read your disk (Brave also blocks the
File System Access API by default). Claude Code / Codex / OpenCode avoid this by
running a local process with filesystem tools. The **desktop companion** is that
local process for the Studio, and it removes the old URL/token paste:

```bash
# one click: starts the loopback bridge, then opens the Studio already paired
python -m sid_harness companion --dir C:\Users\jerry\JB            # read-only
python -m sid_harness companion --dir C:\Users\jerry\JB --write    # write available
# the Studio shows "Enable write access" until the user explicitly grants it
```

The companion binds **127.0.0.1 only**, exchanges a per-launch pairing code (in
the URL fragment, never a server log) for the bearer token, and accepts browser
requests only from the SID origins. The workspace is fixed to `--dir`. The loop
reads the **real tree on demand** (`list_files` / `read_file`), not a snapshot.

Write mode is opt-in twice: `--write` makes it *available*, and the user then
clicks **Enable write access** in the Studio (a per-session grant). Applying a
change requires the exact proposal the bridge generated and the user reviewed:
the digest is bound, every path goes through the shared secret/VCS denylist plus
an atomic all-or-nothing write, and a receipt lands in
`~/.sid/bridge/receipts/apply_*.json`. Endpoints: `GET /health`; `POST /pair`,
`/grant-write`, `/revoke-write`, `/run` `{task, model?, test_argv?}` (with
`X-SID-Api-Key`), and `/apply` `{proposal_id, digest}`. The browser cannot choose
the model backend or run tests without the write grant.

Installers (Windows/macOS/Linux, private venv + login autostart) and the
sign/verify chain live in `install/`. `install/prove_brave_apply.py` drives the
whole pair → grant → run → review → apply path in real Brave headless and checks
the disk plus the receipt.

The Studio ships the client half: a **Local bridge** control in the composer
shows the paired workspace and read-only/write state; `pairFromLocation()` takes
the companion's one-click code from the URL fragment, a Chat turn routes to
`POST {url}/run`, and the receipt (model, tools, tests, diff, changed, final
response) plus the real workspace preview render in place. **Enable write
access** posts the explicit grant, and **Apply** posts the reviewed proposal id
and digest. It fails closed and names the reason when the bridge is unreachable
or the pairing is stale — there is no silent fallback to the remote gateway. The harness CLI (`sid run` /
`sid tui`) remains the full-parity product (including `--write`); the Studio's
bridge path is read-only.

## Editor integration + LSP diagnostics (SUB-96)

The VS Code extension under `editors/vscode` is a thin client over this same
engine: **SID: Open Coding Session** runs `sid session start`, **Show Proposed
Diff** opens the receipt's diff, **Approve and Apply** calls `sid apply` (the
same `LocalWorkspace` + repo-policy write path), and **Attach Selection as
Context** prepends the editor selection to the next task.

```bash
python -m sid_harness editor install      # one command; reload VS Code
```

`sid lsp` is the diagnostics server. It publishes real Python compiler
diagnostics (`compile`) on open/change/save and accepts diagnostics forwarded
from VS Code's other language servers through `sid/diagnostics`. The merged feed
is written to `<workspace>/.sid/diagnostics.json`; `sid run` and `sid session`
prepend a data-boundaried `COMPILER DIAGNOSTICS` block to the task and record
`diagnostics: {count, sources, path}` on the receipt. `--no-diagnostics` opts
out for one run. No model call, no tool contract, and no write path are added by
the LSP — it is a diagnostic source for the one loop.

## Scope guards
- SID stays the only model backend (no aggregator).
- No new pricing surface; your plan's unit is unchanged.
- No reimplemented verify/scan — the harness calls the gateway's.
- No vendor/model name is hardcoded into a rule, script default, or gate.
