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
2 changes: 1 addition & 1 deletion tools/spec-loop/.last-sync
Original file line number Diff line number Diff line change
@@ -1 +1 @@
43e4c6eeb6ba99a2ee1796f2a8ee712db1c31738
ccb53a38843646e1d02f97b1a27253b82aa2675d
20 changes: 17 additions & 3 deletions tools/spec-loop/specs/adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,12 @@ by swapping the adapter, not the skill.
## Where it lives

- `tools/gmail/` — private-mail read/draft (drafts to the outbox; never
sends).
sends). Skills draft through the `gmail-plaintext` MCP server's
`check_auth` / `create_draft` tools, which run outside the sandbox, never
by shelling out to `oauth-draft-create` or probing the token file: the
OAuth token under `~/.config/apache-magpie/` is not readable from
sandboxed Bash, and sandbox-lint refuses an `allowRead` grant for it
(#1681).
- `tools/maildir/` — private-mail drafting to a local Maildir spool
(`maildir-draft-create`, plus the read-only `maildir-draft-find` for the
existing-draft check); an offline alternative to Gmail, selected per
Expand Down Expand Up @@ -70,7 +75,9 @@ by swapping the adapter, not the skill.
Reads and writes keep each file's line endings (LF, CRLF or CR, and a
missing final newline), so a field write changes no other byte on a Git
checkout with `core.autocrlf` or an SVN one with `svn:eol-style`; a file
mixing line endings is refused. A test runs the body-field conformance
mixing line endings is refused. Report files and folders it creates are
`0600` and `0700`, readable by their owner only; it never changes the
mode of a file that already exists (#1700). A test runs the body-field conformance
cases through the store on temporary Git and SVN storage and reads them
back from a fresh checkout.
`detect` reports `field_layout` (`default` or `custom`, with the field
Expand All @@ -95,7 +102,14 @@ by swapping the adapter, not the skill.
confirmed host and refuses any write when the token was withheld.
Body fields go through a byte-identical copy of github-body-field's
parser, with wiki `h1.`–`h3.` headings outside closed code blocks read
as `### <Heading>`; `body` exports exactly those fields.
as `### <Heading>`; `body` exports exactly those fields. The CLI takes
an explicit `--deployment {server,cloud}`, which vetted-ops always
passes, so an inherited `JIRA_DEPLOYMENT` cannot switch a Server tracker
to Cloud endpoints (#1683).
- Both tracker backends reach the `magpie-vetted-ops` plugin as generated
copies under `plugins/magpie-vetted-ops/tools/` (the plugin generator's
`copies` table), not symlinks out of the plugin root, so a
self-contained install (Codex, a plugin cache) carries them (#1683).
- `tools/github/` — issues/PRs/labels read + write-back helpers.
Sub-adapters: `tools/github-body-field/` (reads GitHub issue/PR body
structured field sets on the body-field contract — every column-0
Expand Down
5 changes: 5 additions & 0 deletions tools/spec-loop/specs/adoption-and-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,11 @@ committed version with drift detection.
Checker verification during `config` and `upgrade` uses `--no-welcome`;
unreadable optional guides do not suppress actual setup findings, and
guide names cannot select Markdown files outside the shipped guides.
38. A freshly scaffolded `project.md` carries `tracker.platform: TODO`, so
`setup config` asks for the security-tracker backend (`github`,
`jira` or `local-files`) on every first setup with a `security-*` skill
in scope; the Jira steps map labels to whitespace-free names and
require the backend's `doctor` to pass (#1683).

## Validation

Expand Down
26 changes: 24 additions & 2 deletions tools/spec-loop/specs/agent-isolation-sandbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,14 @@ existing sandbox grants can widen the baseline. See `docs/adapters/gemini.md`.
window exists, so the watcher's close signal only sets the flag
`watch_for_stop` polls; Tk's own handler called `Tcl_Exit` inside the
signal and could deadlock the window mid-redraw until force-quit, and a
regression test pins the ordering (#1376). The
regression test pins the ordering (#1376). Visibility never depends on
activation, which macOS 14 made cooperative: a watcher started in the
background can be refused it, so every window is ordered front with
`orderFrontRegardless` at a level above other windows and joins all Spaces
(including a full-screen terminal's), and activation is only asked for
with `activate`, falling back to the deprecated
`activateIgnoringOtherApps:`; a refusal costs the keyboard, not the
window (#1697). The
git the agent runs reads the same global config, so the wrapper's
two files are a `sandbox.filesystem.allowRead` grant of their own
(nothing wider under `~/.claude/`), or every sandboxed signed commit
Expand Down Expand Up @@ -162,6 +169,15 @@ existing sandbox grants can widen the baseline. See `docs/adapters/gemini.md`.
`git --no-pager commit`), never by a fixed argv slice, and
`GuardContext.git_subcommand()` gives contributed guards the same
resolution `gh_subcommand()` gives for `gh` (#1330).
Every guard first unwraps the prefix wrappers that run their argument,
`env` (its GNU / BSD options, clustered short flags and `NAME=value`
assignments, which still count as inline overrides) and `command -p`,
until none is left, so `env git commit …` reaches the same guards as
`git commit …`; `command -v` is a lookup and is left alone. A segment
nested past a generous depth limit, carrying an undocumented `env`
option or another `command` flag, is marked unparsed and refused, and
`env -S` is refused outright, because GNU env splits its string with
escapes `shlex` does not reproduce (#1691, #1694).
Hooks invoke the engine as a bare `python3`; when that resolves to a
pre-3.11 interpreter, the engine re-runs itself under the newest
`python3.N` (3.11+) on `PATH`, and exits 1 with an actionable message
Expand Down Expand Up @@ -245,7 +261,13 @@ existing sandbox grants can widen the baseline. See `docs/adapters/gemini.md`.
the framework checkout's settings (the `gh` read allows, the remaining
exclusions, family-specific domains, personal tool paths), reconciled into
each contributor's `.claude/settings.local.json`. `sandbox-lint` lints the
two merged and keeps every `deny` / `ask` in the floor.
two merged and keeps every `deny` / `ask` in the floor. Its workflow also
runs when `.claude/settings.local.json` changes and fails while that file
is tracked, since a committed copy would load for everyone and its
scalars override the floor's (#1692). sandbox-lint refuses
`~/.config/apache-magpie` in `allowRead`: the Gmail OAuth token there is
read only by the drafting MCP server outside the sandbox, and the
template no longer grants it or the Google API hosts (#1681).
- `.gemini/settings.json` and `.gemini/policies/magpie.toml` — Magpie's Gemini profile: tool-sandboxing and an explicitly loaded User-tier approval policy.
Scoped shell reads are allowed; other shell calls, native edits, and MCP calls ask; listed commands and credential paths deny.
Credential-path denies name the canonical `grep_search`; the native probe verifies its `search_file_content` alias, canonical policy names, and search/multi-file/web/resource argument schemas against the loaded runtime.
Expand Down
9 changes: 9 additions & 0 deletions tools/spec-loop/specs/vetted-command-surface.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,15 @@ Every call spells the base `~/.claude/magpie/<tool>` (AGENTS.md golden rule):
the agent-guard `vetted-ops-spelling` guard refuses an expanded home path,
`$HOME/…` or a relative checkout path for `vetted-op`, `vetted-op-read`,
`vetted-op-tracker` and `adversarial-review`, and names the `~` command.
It accepts the `~` only bare and space-separated: a quoted or escaped `~`,
a quote after it, or the `--project=~/…` form leaves it unexpanded, so uv
gets a directory named `~` and the exclusion does not match. Because an
exclusion matches a command line by its start, the right spelling behind
`env` or `command` still runs sandboxed and is refused with the command to
run instead. The eval wrapper gets the same treatment: any spelling of
`magpie-run-evals.sh` other than the bare `~/.claude/scripts/…` path is
refused (override `MAGPIE_ALLOW_SCRIPT_PATH=1`), because it would run in the
sandbox and every eval case would error ungraded (#1691).
It also refuses an absolute path inside the working tree, and reads `uv`'s
options on either side of `run`. Under Codex it lets a `vetted-op-read`
through from the exact root Codex's own hook substitutes for `~` (the
Expand Down