# stackone-agent-harness

A Claude Code plugin that builds StackOne Falcon connectors through a gated three-phase
flow — **Research → Build → Validate** — designed to run unattended from a single request
to a terminal outcome.

The defining idea: **phase completion is decided by deterministic gate scripts, never by
the model's own judgement.** A phase is done when its gate script exits 0 and the run
state file says so. The model does the work; the scripts decide whether it counts.

## What it does

Given a request like *"Build the Ashby connector with candidates, notes and
applications"*, the plugin:

1. **Research** — enumerates the provider's full documented API surface (auth mechanisms,
   endpoints, parameters, response shapes, pagination, rate limits) into a single
   checkable artifact, `.connector-dev/<provider>/research/<provider>_research.json`.
2. **Build** — projects that research into Falcon connector YAML (a main
   `*.connector.s1.yaml` plus one `*.s1.partial.yaml` per resource), auth block first,
   then actions.
3. **Validate** — re-derives the connector from the provider's **live documentation** and
   reconciles every difference. It deliberately does not compare against the research
   report — that report produced the connector, so comparing the two would certify
   research's own omissions as correct.

Each phase loops: do the work, run the gate, fix what the gate reported, run it again.

The flow never deploys, never connects an account, and never executes anything against a
live API. Every run ends with the same stated limitation: built and verified against the
provider's documentation, not executed against real credentials.

## Install

This plugin is deployed into a project by [@stackone/cli](https://github.com/StackOneHQ/cli), see repo for further details.

### Prerequisites

- **Node.js 20+** — all gate and state scripts are plain Node
- **`@stackone/cli`** — `npm install -g @stackone/cli` (provides `stackone validate`,
  whose verdict the build gate consumes)
- `jq` is **not** required by any gate or state script

The scripts have **zero npm dependencies**: the one library they need (`js-yaml`) is
vendored at `scripts/lib/vendor/js-yaml.cjs` and loaded through `scripts/lib/yaml.js`,
so they run with plain Node in any environment the plugin is copied to — no npm
install, no network.

## Commands

| Command | Purpose |
|---|---|
| `/connector:full` | Build a connector end to end — Research, Build, Validate — gated and unattended |
| `/connector:research` | Phase 1 only — full provider API investigation |
| `/connector:build` | Phase 2 only — build the connector YAML from research data |
| `/connector:validate` | Phase 3 only — re-derive the connector from live docs and reconcile |
| `/connector:status` | Show where a run has got to — phases, scope, open gaps |

Two additional commands (`connector-onboarding`, `connector-test`) live under
`interactive/` because they require a human in the session; they are parked and not yet
wired into the CLI sync (see `interactive/README.md`).

## Agents

| Agent | Phase | Purpose |
|---|---|---|
| `research/resource-endpoint-fetcher` | 1 | Owns endpoint extraction for one resource; spawned in parallel, one per resource |
| `research/use-case-discoverer` | 1 | Generates the dynamic (Layer 3 + 4) use-case catalogs in an isolated context |
| `validation/schema-reviewer` | 3 | Structural pre-testing schema review; writes the `schema-review.json` verdict |
| `validation/provider-comparator` | 3 | Compares the connector against the provider's official API documentation, action by action |

Around 35 skills support these (research investigation, YAML authoring per schema area,
auth-flow variants, corpus-mined connector patterns, validation rules). See
`docs/phases/` for which skills each phase orchestrates.

## The gates

Five scripts under `scripts/gates/`, one shared contract:

| Gate | Checks | Question it answers |
|---|---|---|
| `research.js` | R1–R10 | Has the full documented surface been enumerated, in enough detail to build from? |
| `auth.js` | A1–A12 | Is the auth block right? A sub-gate of Build, run to green **before any action is written** — a wrong auth block is every action broken at once |
| `build.js` | B1–B13 | Was research projected faithfully? Measures built ÷ discovered-in-scope, so a thin build cannot read as 100% |
| `conventions.js` | N1–N13 | Does the YAML follow what the 484 shipped connectors actually do? Every rule is corpus-mined, with its adherence rate stated |
| `validate.js` | V1–V8 | Is the connector the whole truth about the API, per an independent re-read of the live docs? |

### Exit-code contract

```
0  pass — the phase may advance
1  fail — unmet checks and gap records on stdout
2  could not evaluate (missing or malformed state) — a bug, not a gap
```

Gates are deterministic code, never a model call. Every gate supports `--schema` (print
what it reads and checks), `--only R1,R2` (re-run selected checks), and `--scope
<resource>` (re-check one resource after a targeted fix). `build.js` additionally takes
`--cli-ok true|false` to carry the `stackone validate` verdict — omitting it fails B1,
because an unrun check must never read as a passing one.

### Anti-tautology checks

Two checks exist specifically so a loop cannot close by agreeing with itself:

- **A10** requires `.connector-dev/<provider>/build/auth-evidence.json` citing the
  provider's own auth documentation per mechanism.
- **V2** requires per-resource doc-comparison artifacts whose `docsRead` lists the URLs
  actually opened — empty is rejected.

## Run state

All durable state for a run lives in one file:

```
.connector-dev/<provider>/run.json
```

It is written **only** by `scripts/state/run.js` (`init`, `set-scope`, `set-phase`,
`read`, `summary`). A PreToolUse hook blocks Write/Edit on any `run.json`, so completion
stays computed rather than asserted. Re-issuing the original request resumes from this
file; completed phases are skipped. There is no phase-ledger.json.

### Scope contract

`scripts/state/scope.js` turns the customer's request into a durable contract with three
axes — resources, auth mechanisms, sandbox — each recorded as what was resolved and what
was dropped. Named resources are built uncapped; an unscoped request builds the
provider's core use cases under an endpoint cap (30, plus a dependency-closure budget up
to 50), with everything left out accounted for in `dropped[]`, never silently discarded.
The contract is piped straight into `run.js set-scope`.

### Gap ledger and honest outcomes

Every gate failure becomes a gap record in `run.json` with an id, severity, and status.
The ledger is reconciled on every gate run: gaps no longer reported are marked resolved,
a gap that reopens twice after being fixed is forced to `not_fixable` with a written
reason, and new gaps are appended.

Loops end on merit, not on a timer:

- **Two consecutive rounds resolving nothing** → the phase is marked `exhausted`, its
  remaining gaps are recorded, and the run moves on. `exhausted` is a terminal state for
  the phase, not an error.
- **Outcome `complete`** — all three gates passed.
- **Outcome `partial`** — at least one phase exhausted; the connector is delivered with
  its gap list. A connector plus an honest gap list beats no connector.

## Hooks

`hooks/hooks.json` wires the flow into the session:

- **SessionStart** — exports plugin paths, installs node deps on first run, and prints
  any in-flight run's phase status so resumes are one request away.
- **PostToolUse** (Write/Edit on connector YAML) — points at the relevant
  `connector-patterns` reference and the gates to run next.
- **PreToolUse** — blocks hand-edits of `run.json`, blocks `rm` on load-bearing paths
  (including `.connector-dev/`), warns on force-push.
- **Stop / PreCompact** — prints the run's phase status; PreCompact pins the scope
  contract into context so compaction cannot narrow or widen what was asked for.

## Layout

```
plugin/
├── .claude-plugin/plugin.json   # manifest (name, version, skill list)
├── commands/                    # the five slash commands
├── agents/                      # research/ + validation/ subagents
├── skills/                      # ~35 SKILL.md files, grouped by phase
├── scripts/
│   ├── gates/                   # research, auth, build, conventions, validate + runner, connector loader
│   ├── state/                   # run.js, scope.js, domain-catalog.json
│   ├── research/                # deterministic helpers for Phase 1
│   └── lib/                     # safe-path.js
├── hooks/hooks.json
├── interactive/                 # human-in-session commands, parked
└── docs/                        # PATHS.md, phases/, maintenance/
```

## Documentation

- `docs/README.md` — documentation index
- `docs/maintenance/development-lifecycle.md` — how a change moves from first edit to a connector builder
- `docs/phases/` — one file per phase: skills, agents, entry/exit conditions, artifacts
- `docs/PATHS.md` — canonical path conventions for every file the plugin reads or writes
- `scripts/README.md` — script catalog with the gate and state CLI contracts
