syncade 0.6.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- syncade/__init__.py +3 -0
- syncade/__main__.py +6 -0
- syncade/adapters/__init__.py +0 -0
- syncade/adapters/anthropic.py +457 -0
- syncade/adapters/base.py +221 -0
- syncade/adapters/fake.py +73 -0
- syncade/adapters/fake_common.py +29 -0
- syncade/adapters/fake_producer_audit_draft.py +460 -0
- syncade/adapters/fake_reviewer_synth.py +310 -0
- syncade/adapters/openai.py +484 -0
- syncade/adapters/openai_parsing.py +119 -0
- syncade/adapters/producer.py +221 -0
- syncade/adapters/producer_anthropic.py +300 -0
- syncade/adapters/producer_openai.py +226 -0
- syncade/adapters/registry.py +81 -0
- syncade/auth_check.py +554 -0
- syncade/auth_preflight.py +342 -0
- syncade/base_resolution.py +214 -0
- syncade/billing.py +141 -0
- syncade/checks_config.py +113 -0
- syncade/cli/__init__.py +546 -0
- syncade/cli/auth_gate.py +59 -0
- syncade/cli/config_keys.py +135 -0
- syncade/cli/config_list.py +82 -0
- syncade/cli/config_menu_rows.py +166 -0
- syncade/cli/config_mode.py +609 -0
- syncade/cli/config_overrides.py +122 -0
- syncade/cli/config_tui.py +476 -0
- syncade/cli/doctor_mode.py +72 -0
- syncade/cli/gc_mode.py +109 -0
- syncade/cli/install_skill.py +514 -0
- syncade/cli/metrics_mode.py +363 -0
- syncade/cli/modes.py +573 -0
- syncade/cli/parser.py +450 -0
- syncade/cli/parser_types.py +137 -0
- syncade/cli/paths.py +38 -0
- syncade/cli/preflight_paths.py +90 -0
- syncade/cli/resolve.py +116 -0
- syncade/cli/resume_mode.py +324 -0
- syncade/cli/toml_writer.py +410 -0
- syncade/cli/validate.py +421 -0
- syncade/config.py +478 -0
- syncade/config_auth.py +310 -0
- syncade/config_cold.py +209 -0
- syncade/config_gc.py +55 -0
- syncade/config_loader.py +182 -0
- syncade/config_loop.py +282 -0
- syncade/config_producer.py +222 -0
- syncade/config_retry.py +49 -0
- syncade/config_types.py +59 -0
- syncade/diff_filter.py +437 -0
- syncade/dispatcher.py +571 -0
- syncade/doctor.py +425 -0
- syncade/doctor_env.py +218 -0
- syncade/doctor_preview.py +524 -0
- syncade/doctor_types.py +28 -0
- syncade/exit_codes.py +82 -0
- syncade/findings.py +242 -0
- syncade/findings_json.py +456 -0
- syncade/gc.py +211 -0
- syncade/gc_execute.py +372 -0
- syncade/gc_protection.py +129 -0
- syncade/gc_types.py +50 -0
- syncade/gc_worktrees.py +200 -0
- syncade/git_object_id.py +12 -0
- syncade/git_preconditions.py +389 -0
- syncade/logging.py +289 -0
- syncade/metrics/__init__.py +32 -0
- syncade/metrics/aggregate.py +550 -0
- syncade/metrics/schema.py +221 -0
- syncade/orchestrator/__init__.py +61 -0
- syncade/orchestrator/_runs_dir.py +24 -0
- syncade/orchestrator/branch_advance.py +165 -0
- syncade/orchestrator/branch_guard.py +98 -0
- syncade/orchestrator/budget.py +107 -0
- syncade/orchestrator/escalation_coverage.py +81 -0
- syncade/orchestrator/loop.py +611 -0
- syncade/orchestrator/loop_dispatch_check.py +112 -0
- syncade/orchestrator/loop_finalize.py +404 -0
- syncade/orchestrator/loop_preflight.py +131 -0
- syncade/orchestrator/loop_resume.py +91 -0
- syncade/orchestrator/loop_rmtree.py +70 -0
- syncade/orchestrator/loop_round_step.py +599 -0
- syncade/orchestrator/prior_round.py +336 -0
- syncade/orchestrator/producer_phase.py +169 -0
- syncade/orchestrator/results.py +306 -0
- syncade/orchestrator/resume.py +96 -0
- syncade/orchestrator/resume_load.py +483 -0
- syncade/orchestrator/resume_plan.py +554 -0
- syncade/orchestrator/resume_target.py +215 -0
- syncade/orchestrator/resume_types.py +182 -0
- syncade/orchestrator/reviewer_template_failure.py +99 -0
- syncade/orchestrator/round.py +573 -0
- syncade/orchestrator/round_checks.py +91 -0
- syncade/orchestrator/round_no_changes.py +369 -0
- syncade/orchestrator/round_predispatch.py +212 -0
- syncade/orchestrator/verdict.py +279 -0
- syncade/persistence/__init__.py +189 -0
- syncade/persistence/_atomic.py +33 -0
- syncade/persistence/_clusters.py +70 -0
- syncade/persistence/_findings_verdict.py +201 -0
- syncade/persistence/_markdown.py +286 -0
- syncade/persistence/_validation.py +37 -0
- syncade/persistence/checks.py +249 -0
- syncade/persistence/decision_needed.py +289 -0
- syncade/persistence/findings_md.py +389 -0
- syncade/persistence/handoff.py +389 -0
- syncade/persistence/handoff_classify.py +196 -0
- syncade/persistence/last_reviewed.py +67 -0
- syncade/persistence/loop_manifest.py +165 -0
- syncade/persistence/loop_summary.py +352 -0
- syncade/persistence/loop_summary_text.py +428 -0
- syncade/persistence/producer.py +250 -0
- syncade/persistence/reviewer.py +198 -0
- syncade/persistence/round_manifest.py +238 -0
- syncade/persistence/run_init.py +153 -0
- syncade/persistence/run_summary.py +585 -0
- syncade/persistence/run_summary_next_steps.py +443 -0
- syncade/persistence/synth.py +242 -0
- syncade/persistence/test_run.py +152 -0
- syncade/presets.py +36 -0
- syncade/pricing_config.py +72 -0
- syncade/process.py +600 -0
- syncade/producer.py +189 -0
- syncade/producer_attempt.py +463 -0
- syncade/producer_escalation.py +146 -0
- syncade/producer_git.py +199 -0
- syncade/producer_result.py +205 -0
- syncade/prompts.py +448 -0
- syncade/prompts_loader.py +238 -0
- syncade/retry.py +159 -0
- syncade/run_inputs.py +40 -0
- syncade/run_status.py +198 -0
- syncade/selfcheck.py +471 -0
- syncade/skills/claude/README.md +221 -0
- syncade/skills/claude/SKILL.md +625 -0
- syncade/skills/codex/README.md +116 -0
- syncade/skills/codex/SKILL.md +574 -0
- syncade/snapshot.py +598 -0
- syncade/spec_audit.py +437 -0
- syncade/spec_audit_schema.py +190 -0
- syncade/spec_draft.py +423 -0
- syncade/spec_source.py +135 -0
- syncade/synthesis.py +428 -0
- syncade/synthesis_clusters.py +203 -0
- syncade/synthesis_repair.py +230 -0
- syncade/synthesis_schema.py +65 -0
- syncade/synthesizer/__init__.py +38 -0
- syncade/synthesizer/constants.py +33 -0
- syncade/synthesizer/driver.py +531 -0
- syncade/synthesizer/rendering.py +63 -0
- syncade/synthesizer/result.py +73 -0
- syncade/synthesizer/validation.py +421 -0
- syncade/synthesizer/workspace.py +208 -0
- syncade/templates/presets/balanced.toml +13 -0
- syncade/templates/presets/cheap.toml +12 -0
- syncade/templates/presets/thorough.toml +9 -0
- syncade/templates/producer.md +231 -0
- syncade/templates/reviewer.md +279 -0
- syncade/templates/reviewer_adversarial.md +164 -0
- syncade/templates/reviewer_codex.md +165 -0
- syncade/templates/spec_audit.md +168 -0
- syncade/templates/spec_draft.md +62 -0
- syncade/templates/synthesizer.md +204 -0
- syncade/test_runner.py +476 -0
- syncade/test_runner_classify.py +98 -0
- syncade/transcript.py +150 -0
- syncade/usage.py +407 -0
- syncade/worktree.py +497 -0
- syncade/worktree_env.py +133 -0
- syncade/worktree_paths.py +139 -0
- syncade-0.6.2.dist-info/METADATA +314 -0
- syncade-0.6.2.dist-info/RECORD +177 -0
- syncade-0.6.2.dist-info/WHEEL +5 -0
- syncade-0.6.2.dist-info/entry_points.txt +2 -0
- syncade-0.6.2.dist-info/licenses/LICENSE +202 -0
- syncade-0.6.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# syncade Claude Code skill
|
|
2
|
+
|
|
3
|
+
Bridge between Claude Code's slash-command interface and the syncade
|
|
4
|
+
external review orchestrator. Operators type `/syncade <pr-doc>` from
|
|
5
|
+
inside Claude Code; this skill orchestrates the safety check
|
|
6
|
+
+ confirmation gate + the actual review loop, then summarizes inline.
|
|
7
|
+
|
|
8
|
+
## Quick start
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
/syncade path/to/pr.md
|
|
12
|
+
/syncade review path/to/pr.md for 2 rounds against main
|
|
13
|
+
/syncade dogfood a PR single pass
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The skill also handles **configuration** without running a review — "/syncade config",
|
|
17
|
+
"change my producer to gpt-5", "set rounds to 2", "show my config" — rendering a config
|
|
18
|
+
**menu** (`syncade --config list --all`) you browse and edit via
|
|
19
|
+
`syncade --config set <key> <value>` (writes the global `~/.syncade/config.toml`, or the
|
|
20
|
+
repo's with `--repo`). See "Configuring syncade" in the SKILL.
|
|
21
|
+
|
|
22
|
+
Both the structured form and clear natural language work: the skill
|
|
23
|
+
maps your request onto the CLI shape `syncade [--openspec [ID] | PR_DOC]
|
|
24
|
+
[--base REF | --scope SCOPE] [--max-rounds N]` — at the skill (markdown) layer
|
|
25
|
+
only; the skill adds no Python of its own (PR-B added `--scope`, PR-C added
|
|
26
|
+
`--openspec`, the flags it targets). The interactive Claude will:
|
|
27
|
+
|
|
28
|
+
0. **Resolve intent** — turn natural language into an exact command. It asks
|
|
29
|
+
one short question if the target / round count / base is ambiguous, and
|
|
30
|
+
**maps scope phrases** ("review what I just did" → `--scope local`,
|
|
31
|
+
"everything" → `--scope everything`, "since last review" →
|
|
32
|
+
`--scope since-last-review`) onto the `--scope` flag (PR-B); Python derives
|
|
33
|
+
the concrete base, the skill never hand-picks one.
|
|
34
|
+
1. Validate the resolved PR doc is readable (and any explicit base ref).
|
|
35
|
+
2. Run `syncade --auth-check` (~5–10 s safety check).
|
|
36
|
+
3. Run `syncade --selfcheck` (~30 s safety check).
|
|
37
|
+
4. Print the safety-check result + the EXACT resolved command + expected
|
|
38
|
+
timing and ask you to confirm with `go` / `cancel`. After the safety check
|
|
39
|
+
the skill goes straight to the reviewer loop — no brief-check, no automatic
|
|
40
|
+
spec-audit in between.
|
|
41
|
+
5. On `go`, run the resolved command and stream output to chat.
|
|
42
|
+
6. Read `<run-dir>/loop-summary.md` and print the verdict + round
|
|
43
|
+
count + finding count.
|
|
44
|
+
7. If the producer committed, list each commit with its short SHA +
|
|
45
|
+
subject and a `git reset --hard <round-0-sha>` rollback pointer.
|
|
46
|
+
|
|
47
|
+
### Natural-language phrasings the skill understands
|
|
48
|
+
|
|
49
|
+
- **Round count:** `for 1 round`, `for 2 rounds`, `max rounds 3`, `single pass`
|
|
50
|
+
(= 1 round). Valid: 1–10. Omit it and your config's `max_rounds` stays
|
|
51
|
+
authoritative.
|
|
52
|
+
- **Base ref:** `against main`, `from origin/main`, `base HEAD~3`, or literal
|
|
53
|
+
`--base <ref>` (validated with `git rev-parse` before running). Omit it and
|
|
54
|
+
current CLI behavior stays authoritative.
|
|
55
|
+
- **Scope (PR-B):** `everything` (the branch point off the default branch),
|
|
56
|
+
`what I just did` / `my recent changes` (`--scope local` — local-ahead
|
|
57
|
+
commits vs the branch's upstream), `since last review` / `what's new`
|
|
58
|
+
(`--scope since-last-review` — the recorded last-reviewed SHA for this
|
|
59
|
+
branch). Mutually exclusive with an explicit base ref; an explicit ref wins.
|
|
60
|
+
`local` with no upstream and `since-last-review` with no prior record fall
|
|
61
|
+
back to the branch point with a one-line note rather than erroring.
|
|
62
|
+
- **OpenSpec (PR-C):** `review the openspec change <id>` / `run syncade on my
|
|
63
|
+
openspec proposal` → `--openspec <id>` (or bare `--openspec` to auto-resolve a
|
|
64
|
+
single active change). syncade assembles `openspec/changes/<id>/` (proposal +
|
|
65
|
+
spec deltas) into the spec it reviews against — reading the markdown directly,
|
|
66
|
+
no `openspec` binary needed. Replaces the PR-doc path (one spec source);
|
|
67
|
+
`--base`/`--scope` still set the diff base.
|
|
68
|
+
- **Draft-spec / tier C (PR-D + PR-E):** no brief at all? `I didn't write a spec,
|
|
69
|
+
review what we did` / `draft a spec from this session`. A cold drafter reads the
|
|
70
|
+
session transcript for *intent* (the skill resolves the transcript path; it never
|
|
71
|
+
summarizes the conversation itself) and writes a draft spec with an "Assumptions
|
|
72
|
+
to confirm" section. **PR-E ties this into one pane:** syncade drafts → you
|
|
73
|
+
**ratify it right here in chat** (it shows the draft + the flagged assumptions
|
|
74
|
+
verbatim and asks "what did I miss?"; your corrections edit the spec) → the blind
|
|
75
|
+
review loop runs — no second command. A manufactured spec is never reviewed
|
|
76
|
+
against unratified.
|
|
77
|
+
- **Target:** an explicit path always wins; a PR number / `this PR` resolve only
|
|
78
|
+
when exactly one readable PR doc matches, else the skill asks.
|
|
79
|
+
|
|
80
|
+
## Prerequisites
|
|
81
|
+
|
|
82
|
+
- `claude` CLI installed and authenticated (`claude --version` works).
|
|
83
|
+
- `codex` CLI installed and authenticated (`codex login status`
|
|
84
|
+
reports "Logged in...").
|
|
85
|
+
- `syncade` installed and on `PATH` (`syncade --version` works from any
|
|
86
|
+
directory — see the repo README's "Global install").
|
|
87
|
+
- macOS or Linux (the skill assumes `bash` / `zsh`; Windows-WSL is
|
|
88
|
+
fine the same way running `syncade` manually is).
|
|
89
|
+
|
|
90
|
+
## When to use vs. terminal
|
|
91
|
+
|
|
92
|
+
| Situation | Skill | Terminal |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| First syncade run on a PR brief | yes — gets you pre-flight diagnostics + confirmation gate | works, but you'll want to run `--auth-check` and `--selfcheck` yourself |
|
|
95
|
+
| Repeat dogfood after a code change | yes — same pre-flights catch token rotation cheaply | yes if you've already verified your auth recently |
|
|
96
|
+
| You only want auth diagnostics, not a review | no — terminal: `syncade --auth-check` is ~5 s | yes |
|
|
97
|
+
| You only want producer-commit diagnostics | no — terminal: `syncade --selfcheck` is ~30 s | yes |
|
|
98
|
+
| You only want a spec audit of the brief | no — terminal: `syncade --spec-audit <pr-doc>` (manual; not part of the skill flow) is ~30–90 s | yes |
|
|
99
|
+
| Resuming a prior run | terminal: `syncade --resume <run-id>` | yes |
|
|
100
|
+
|
|
101
|
+
The skill is opt-in. Operators running `syncade <pr-doc>` from a
|
|
102
|
+
terminal still get the same loop; they just don't get the pre-flight
|
|
103
|
+
+ confirmation gate.
|
|
104
|
+
|
|
105
|
+
## Failure modes
|
|
106
|
+
|
|
107
|
+
### Auth-check fails (step 2)
|
|
108
|
+
|
|
109
|
+
The skill stops. Output shows which provider failed and the
|
|
110
|
+
remediation:
|
|
111
|
+
|
|
112
|
+
- `[auth-check] anthropic: FAILED (...). Run 'claude' interactively to re-authenticate.`
|
|
113
|
+
- `[auth-check] openai: FAILED (...). Run 'codex login' to re-authenticate.`
|
|
114
|
+
|
|
115
|
+
Fix the named provider and re-run `/syncade <pr-doc>`.
|
|
116
|
+
|
|
117
|
+
### Selfcheck fails (step 3)
|
|
118
|
+
|
|
119
|
+
The skill stops. Common causes:
|
|
120
|
+
|
|
121
|
+
- **Producer stalled** — the producer edited files but never
|
|
122
|
+
committed, so the round has nothing to accept. This is not a
|
|
123
|
+
permissions misconfiguration: `[producer] permissions` accepts
|
|
124
|
+
**only** `"yolo"` (schema-enforced), precisely because sandboxed
|
|
125
|
+
modes cannot commit headlessly — claude's `acceptEdits` prompts for
|
|
126
|
+
bash, and codex's `workspace-write` blocks `.git/index.lock` writes.
|
|
127
|
+
Look at the producer's own output instead: it usually means the model
|
|
128
|
+
described a fix without running `git commit`.
|
|
129
|
+
- **Producer subprocess error** — the producer CLI itself failed.
|
|
130
|
+
The selfcheck workspace is preserved; the path is the last stderr
|
|
131
|
+
line. `cat <workspace>/round-0/producer.error.txt` for the cause.
|
|
132
|
+
- **Producer committed but didn't add the marker** — the producer's
|
|
133
|
+
prompt template may be broken. Inspect
|
|
134
|
+
`<workspace>/round-0/producer.stdout` to see what it actually did.
|
|
135
|
+
|
|
136
|
+
### Operator cancels at step 4
|
|
137
|
+
|
|
138
|
+
The skill prints `[syncade] cancelled at operator confirmation` and
|
|
139
|
+
exits. Nothing was modified.
|
|
140
|
+
|
|
141
|
+
### `syncade <pr-doc>` fails mid-loop (step 5)
|
|
142
|
+
|
|
143
|
+
The skill still tries to read `loop-summary.md`. If it exists, the
|
|
144
|
+
verdict is presented; if not, the skill points at the highest-numbered
|
|
145
|
+
round dir under `<run-dir>/`. Common exit codes:
|
|
146
|
+
|
|
147
|
+
| Exit | Meaning | Where to look |
|
|
148
|
+
|---|---|---|
|
|
149
|
+
| 20 | max rounds reached, no SHIP | every round's `findings.md` |
|
|
150
|
+
| 25 | stopped at a phase boundary — YOUR budget ceiling, or the PROVIDER's usage limit (the summary says which) | resume with `syncade --resume`; raise the limit if it was yours, wait for the window if it was the provider's |
|
|
151
|
+
| 30 | non-dismissed blocker, or producer stalled, or tests failed | last round's `findings.md` or `test-run.stdout` |
|
|
152
|
+
| 40 | reviewer/synthesizer/producer subprocess error | last round's `<provider>.stderr` or `producer.error.txt` |
|
|
153
|
+
| 50 | config error | the message says exactly which TOML field |
|
|
154
|
+
| 60 | worktree error or dirty-tree refusal | the message names the cause |
|
|
155
|
+
| 70 | output unparseable | `<reviewer>.stdout` for the actual reviewer output |
|
|
156
|
+
|
|
157
|
+
Full table at the exit-code table.
|
|
158
|
+
|
|
159
|
+
## Producer commits on your branch
|
|
160
|
+
|
|
161
|
+
When `max_rounds > 1` (the default), the producer can commit to the
|
|
162
|
+
current branch between rounds. The blast radius:
|
|
163
|
+
|
|
164
|
+
- **Each producer commit lands on the operator's branch**, not on a
|
|
165
|
+
separate branch. Reviewer worktrees share `.git`, so the next
|
|
166
|
+
round's reviewers see the new commit.
|
|
167
|
+
- **Branch advance is fast-forward only.** If the producer makes an
|
|
168
|
+
orphan commit (which shouldn't happen — the producer's prompt
|
|
169
|
+
requests a real commit on top of HEAD), the orchestrator refuses
|
|
170
|
+
to advance the branch and exits 30 with `producer_stalled`.
|
|
171
|
+
- **Step 7 of the skill surfaces every commit** with its SHA + subject
|
|
172
|
+
before declaring the run done. Inspect each via `git show <sha>`
|
|
173
|
+
before merging.
|
|
174
|
+
- **Rollback is `git reset --hard <round-0-starting-sha>`**. The
|
|
175
|
+
starting SHA is in `<run-dir>/loop-manifest.json` at
|
|
176
|
+
`rounds[0].snapshot.commit_sha`. The skill prints this command in
|
|
177
|
+
step 7; you don't have to look it up.
|
|
178
|
+
|
|
179
|
+
If you want to keep some producer commits and reject others, use
|
|
180
|
+
`git reset --hard <round-0-sha>` + `git cherry-pick <sha>` for the
|
|
181
|
+
ones you keep, or `git revert <sha>` to invert specific ones in
|
|
182
|
+
place.
|
|
183
|
+
|
|
184
|
+
## What the skill does not do
|
|
185
|
+
|
|
186
|
+
- Doesn't reimplement syncade. It's a Bash wrapper over the syncade
|
|
187
|
+
CLI; everything the skill does is also doable from a terminal.
|
|
188
|
+
- Doesn't review code itself. The interactive Claude reading this
|
|
189
|
+
skill is the operator's UI, not a syncade reviewer. The reviewer
|
|
190
|
+
subprocesses (`claude -p`, `codex exec`) run with no shared
|
|
191
|
+
context with this session.
|
|
192
|
+
|
|
193
|
+
## Where this skill lives
|
|
194
|
+
|
|
195
|
+
`.claude/skills/syncade/` in the syncade repo, so `/syncade` is available only
|
|
196
|
+
when you work inside this repo.
|
|
197
|
+
|
|
198
|
+
**To use it in any project**, install it at the user level with one command:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
syncade --install-skill claude # copies it to ~/.claude/skills/syncade/
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
This works from any installed copy of syncade (the skill ships inside the
|
|
205
|
+
package) — `pip install .` from a checkout, or `pip install git+<repo-url>`.
|
|
206
|
+
syncade is not published on PyPI. Skills load at session start, so restart Claude Code (or open a session
|
|
207
|
+
in the target project) to pick it up. The `syncade` CLI it shells out to must be on
|
|
208
|
+
your `PATH`. Developers who want the installed skill to track a checkout can
|
|
209
|
+
`ln -sfn "$PWD/.claude/skills/syncade" ~/.claude/skills/syncade` instead.
|
|
210
|
+
|
|
211
|
+
## Codex counterpart (single source)
|
|
212
|
+
|
|
213
|
+
There is a sibling Codex skill at `.codex/skills/syncade/` (install into
|
|
214
|
+
`~/.codex/skills/`). It is the **same** skill: the load-bearing Step 2 →
|
|
215
|
+
Invariants workflow span is shared and kept byte-identical by
|
|
216
|
+
`tests/skills/test_skill_drift.py` — the two copies are wrapped in
|
|
217
|
+
`<!-- SYNCADE-SHARED:start/end -->` markers, and **any edit to the shared span
|
|
218
|
+
must be made in both copies** or the drift test fails. Only the harness-specific
|
|
219
|
+
head differs (invocation phrasing; Claude's tier-C draft-from-session vs the
|
|
220
|
+
Codex copy's graceful degrade, which lands draft-from-session in a follow-up; and
|
|
221
|
+
`CLAUDE.md` vs `AGENTS.md`). See the Codex skill format and `path/to/pr.md` for the brief.
|