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
20 changes: 14 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ jobs:
- name: Run pi agent-kit offline verification
run: bash pi-coding-agent/scripts/verify

- name: Run first-mate skill-kit offline verification
run: bash first-mate-skill/scripts/verify

- name: Set up Python
uses: actions/setup-python@v5
with:
Expand All @@ -56,7 +59,7 @@ jobs:
ref: a290d5d80737fc739e7ec139da0eeaf438631631
path: .patterns

- name: Validate pi agent-kit spec with the patterns validator (when present)
- name: Validate agent-kit and skill-kit specs with the patterns validator (when present)
shell: bash
run: |
set -euo pipefail
Expand All @@ -68,13 +71,18 @@ jobs:
exit 0
fi
work="$(mktemp -d)"
kit="$work/integrations/isolation/acq-kits/pi-coding-agent"
mkdir -p "$work/schemas" "$kit"
mkdir -p "$work/schemas" "$work/integrations/isolation/acq-kits"
cp "$schema" "$work/schemas/"
cp pi-coding-agent/spec.yaml pi-coding-agent/README.md "$kit/"
cp -R pi-coding-agent/files "$kit/files"
printf 'schemaVersion: "acq-kits-registry/v1"\nkits:\n pi-coding-agent:\n backends: [sbx, msb]\n parity: CI validation entry.\n' \
printf 'schemaVersion: "acq-kits-registry/v1"\nkits:\n' \
> "$work/integrations/isolation/acq-kits/kits.yaml"
for name in pi-coding-agent first-mate-skill; do
kit="$work/integrations/isolation/acq-kits/$name"
mkdir -p "$kit"
cp "$name/spec.yaml" "$name/README.md" "$kit/"
cp -R "$name/files" "$kit/files"
printf ' %s:\n backends: [sbx, msb]\n parity: CI validation entry.\n' "$name" \
>> "$work/integrations/isolation/acq-kits/kits.yaml"
done
python "$validator" --root "$work" --strict

- name: Validate provider input with a patched credential binding
Expand Down
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Agentic Coding Kits

Provider kits and agent kits for
Provider kits, agent kits, and skill kits for
[`acq`](https://github.com/GSA-TTS/agentic-coding-quickstart), the sandbox
wrapper used by the GSA-TTS
[agentic-coding-quickstart](https://github.com/GSA-TTS/agentic-coding-quickstart)
Expand All @@ -9,13 +9,16 @@ project.
- A **provider kit** describes a model provider once, in a harness-neutral form:
protocol, host, base URL, models URL, credential variable name, and a neutral
model catalog. It names no coding agent and writes no agent configuration.
- A **skill kit** drops an Agent Skill into the guest's skills root. It installs
nothing, runs nothing, and needs no network access.
- An **agent kit** installs a coding agent and renders the selected provider
generation into that agent's own configuration. It owns the agent config and
nothing else.

The two compose at sandbox creation: a provider that speaks the provider's
protocol can be consumed by any agent kit that implements the neutral → harness
mapping.
mapping. A skill kit is independent of both and composes with any
of them.

This repository is separate from
[agentic-coding-patterns](https://github.com/GSA-TTS/agentic-coding-patterns),
Expand Down Expand Up @@ -59,6 +62,7 @@ An agent kit is a `hybrid/v1` mixin that:
| --- | --- | --- | --- |
| [`opencode-go-provider/`](opencode-go-provider/) | Provider | OpenCode Go (`openai-compatible`) facts and a 19-model neutral catalog | **Preview** — blocked on the acq credential-binding addition |
| [`pi-coding-agent/`](pi-coding-agent/) | Agent | Pinned pi CLI + `~/.pi/agent/models.json` renderer | **Preview** — live verification pending acq PR 611 |
| [`first-mate-skill/`](first-mate-skill/) | Skill | The `paseo-first-mate` Agent Skill and two helper scripts, dropped into `~/.agents/skills` | Offline-verified; no live sandbox run |

**Preview status.**

Expand Down Expand Up @@ -100,6 +104,11 @@ pi-coding-agent/ agent kit
scripts/verify offline gate + optional live acq/msb check
tests/ node:test suite, fixtures, vendored schemas
docs/decisions/ design records
first-mate-skill/ skill kit
spec.yaml hybrid/v1 mixin definition (file drops only)
files/home/.agents/skills/ the paseo-first-mate skill and its assets
scripts/verify offline gate
docs/decisions/ design records
```

New kits follow the same directory contract and get a row in the table above.
Expand Down
105 changes: 105 additions & 0 deletions first-mate-skill/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# first-mate-skill (acq mixin kit, `hybrid/v1`)

An [`acq`](https://github.com/GSA-TTS/agentic-coding-quickstart) **skill kit**.
It drops the `paseo-first-mate` Agent Skill into the sandbox so a coding agent
can coordinate a multi-issue engineering effort through isolated Paseo
workspaces and GitHub: delegate work, track dependent pull requests, wait on
changes cheaply, and keep a durable handoff.

It is an opt-in `--kit` mixin. It installs no agent, writes no provider
configuration, runs no commands, publishes no ports, and allow-lists no
network hosts.

## What it ships

```text
~/.agents/skills/paseo-first-mate/
SKILL.md the skill (version 1.2.0 at authorship)
assets/first-mate-check.py change detector (prints nothing when nothing changed)
assets/first-mate-wait.sh background wait loop around the detector
```

`~/.agents/skills` is the cross-agent skills root that the supported agents scan,
so no per-agent linking is needed.

The payload is written at its final path by the kit's `files[]` records, which
is why the spec has no `commands`. Nothing can fail at startup beyond the file
drop itself.

## Using the kit

Pin the ref to a full commit SHA and select the subdirectory with `&dir=`.
Never use `#ref=main`: a branch ref lets the host fetch different code at a
different time.

```bash
export ACQ_EXTRA_KIT_SOURCES="github.com/mogul/"

acq run opencode /path/to/project \
--kit "git+https://github.com/mogul/agentic-coding-kits.git#ref=<full-sha>&dir=first-mate-skill"
```

To apply it on every run, put the same ref in `ACQ_EXTRA_KITS`. Extra kits apply
after the built-ins, and acq resolves overlapping file paths last-wins; that
rule is confirmed in the sbx translator and not separately checked on msb.

Then ask the agent to coordinate an effort ("act as first mate for these
issues"). The skill tells it to copy `assets/` into the coordinator worktree's
git-ignored `tmp/` before using the scripts.

## What the helper scripts need

The detector is a Python 3 script and the wait loop is bash. They call the `gh`
and `paseo` CLIs when the agent runs them. This kit installs none of `python3`,
`gh`, or `paseo` and does not allow-list `api.github.com`; kits cannot declare
dependencies yet, so those must come from the sandbox image, its other kits, and
secret bindings. A missing tool is reported rather than hidden: the detector
prints an `ERROR` line naming the missing CLI, and the shell reports a missing
`python3`. The detector only reads GitHub and Paseo state; its only writes are
the state and watch files, and the directory that holds them, `FIRST_MATE_DIR`
(default `./tmp`, relative to the current directory).

## Updating the skill

The skill is a **one-time snapshot** of the author's working copy, not a synced
copy; see [`docs/decisions/0001`](docs/decisions/0001-ship-the-first-mate-skill-as-a-snapshot-kit.md).
To update it:

1. Replace `SKILL.md` and the two `assets/` files under
`files/home/.agents/skills/paseo-first-mate/`.
2. Keep each file's mode in `spec.yaml` (`0644` for `SKILL.md`, `0755` for the
scripts).
3. If you add or remove a file, add or remove its `files[]` record. msb
materializes only the listed records.
4. Run `scripts/verify`.
5. Recreate the sandbox. `acq kit apply` re-applies the spec to an existing
sandbox, but a new kit commit is a new ref, so a fresh `acq run` is the
reliable path.

## Verifying the kit

```bash
scripts/verify
```

The offline gate checks that the spec and `files/` agree, the declared modes and
the scripts' executable bits, the skill's frontmatter and asset references, that
both helper scripts parse, that the detector runs against an empty state
directory, that no credential-shaped string is shipped, and `acq kit validate`
when available. `shellcheck` runs when installed. There is no live sandbox
check: the kit only drops files, so a live run would exercise acq's file drop
rather than this kit.

## Security notes

- **No secrets.** The skill and scripts reference credentials by variable name
only, in prose. `scripts/verify` scans the payload for token and key shapes.
- **Instructions are executable influence.** A skill steers an agent that can
run commands and push code. The skill is plain text you can read in this
directory; review it before pinning a new SHA.
- **Agent-writable.** The files land under `/home/agent`, which the agent owns.
They are a convenience payload, not a trust anchor.

## License

MIT — see the repository [`LICENSE`](../LICENSE).
50 changes: 50 additions & 0 deletions first-mate-skill/TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Troubleshooting — first-mate-skill kit

## The agent does not list or load `paseo-first-mate`

- **Check the file landed.**

```bash
acq exec <sandbox> -- ls -l /home/agent/.agents/skills/paseo-first-mate
```

Expect `SKILL.md` and `assets/`. If it is missing, the kit was not applied:
confirm `ACQ_EXTRA_KIT_SOURCES` includes `github.com/mogul/`, the ref is a
full SHA, and `&dir=first-mate-skill` is present.
- **Start a new session.** Agents usually discover skills at startup.

## `first-mate-wait.sh: Permission denied`

The scripts are declared `0755`. On sbx, every `files/` payload is first
materialized at `0644` and a combined chmod step restores the declared modes;
if that step did not run, run the script as `bash first-mate-wait.sh` or
`chmod +x` the two files.

## `python3`, `gh`, or `paseo`: command not found

The detector needs `python3` and shells out to `gh` and `paseo`. This kit
installs none of them.
Use an image or kit that provides them, and make sure GitHub access is bound
through acq's secret flow. The detector treats a transient API error as "keep
the previous value" and reports it, so a missing `gh` or `paseo` shows up as an
`ERROR` line on every run, which makes the wait loop return immediately each
time. A missing `python3` also makes the wait loop return at once, with the
shell's "command not found" as its output.

## The detector prints nothing and the wait loop never returns

That is the intended quiet path: once a baseline exists, it prints nothing when
nothing changed, and the wait loop exits 3 at its cap. The very first run prints
`BASELINE saved` (even with an empty watch list, because agents and permission
prompts are always collected), so the wait loop returns once at first start;
restart it after that. If `paseo` is missing the baseline never settles (see the
previous section), so the loop returns every time. Run the script with `--show`
to see the full current snapshot, and `list` to see what is being watched. State
and watch files live in `FIRST_MATE_DIR` (default `./tmp`), relative to where
you run the script.

## An edit to the skill does not show up in a running sandbox

The kit is applied from a pinned SHA. Push the change, pin the new SHA, and
create a new sandbox. Editing the files inside a running sandbox changes that
sandbox only.
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Decision: ship the First Mate skill as a snapshot kit at its final path

**Status:** accepted (2026-10-29)

## Context

The `paseo-first-mate` skill is a single `SKILL.md` plus two helper scripts
(a change detector and a wait loop). The author wants it available inside every
acq sandbox, as a personal skill, without editing the playbook kit or the image.
acq's extension point for that is an opt-in `hybrid/v1` mixin applied with
`--kit` or `ACQ_EXTRA_KITS`.

The skill is still being developed in a separate working copy.

## Decision

1. **A mixin kit that only drops files.** The spec has `files[]` records and
nothing else: no `commands`, no `caps.network`, no `agent:`, no ports. The
skill needs no install step, and the scripts' network use (`gh`, `paseo`)
belongs to the kits and image that provide those CLIs.

2. **Write the payload at its final path, `~/.agents/skills/paseo-first-mate/`.**
This is the cross-agent skills root that the supported agents scan. The
playbook kit instead extracts a tree elsewhere and symlinks entries into
several roots, with integrity and symlink guards.
That machinery protects against a tampered tarball; this kit has no
download, so it has nothing to guard and no reason to add a link step that
could fail. The playbook kit links its own skill names into the same
directory; none of them is `paseo-first-mate`, and both write as the agent
user, so the two do not collide.

3. **A one-time snapshot, not a synced copy.** The files were copied once from
the author's working copy at skill version 1.2.0, and later edits are applied
by replacing the files by hand. Considered and rejected for now: a sync
script that copies from the working copy into the kit. A snapshot keeps this
repository self-contained and reviewable by SHA, and avoids a script that
reaches into a path that exists on one machine. If the skill starts changing
often, add the sync script then.

4. **Declared modes.** `SKILL.md` is `0644`; the two scripts are `0755`. The
skill tells the agent to copy the scripts into a git-ignored worktree
directory before use. They stay executable so the copy keeps working
and so `bash` and direct invocation both work.

5. **Verification is offline.** `scripts/verify` checks the spec against the
tree, modes, frontmatter, script syntax, and a credential-pattern scan, and
runs `acq kit validate` when `acq` is present. A live sandbox run would
mostly exercise acq's file drop, not anything this kit decides.

6. **Two edits to the snapshot.** Relative to the working copy, the skill's
`owners` is `@mogul` (this repository's owner), and the dangling
`pattern-router` line in "Related Patterns" is removed because that pattern
does not exist here.

## Consequences

- The kit adds no egress, no startup work, and no failure modes beyond the file
drop.
- Updating the skill is a manual replace plus `scripts/verify` plus a new pinned
SHA.
- The spec's `files[]` list and the `files/` tree must be kept equal by hand;
`scripts/verify` enforces it, because msb materializes only listed records.
Loading
Loading