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
137 changes: 114 additions & 23 deletions AGENTS.colleague.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,54 @@
# Colleague Resident — `substack-cli`

You are a colleague session working in a clone of this template — reading
this file because colleague's prompt cascade resolves it here, not because
`culture.yaml` selected you. That declaration says `backend: claude`, so
`CLAUDE.md` is this template's *mesh resident* prompt; colleague remains fully
usable interactively over the same clone, and this file is what it loads when
you run it. A clone that declares `backend: colleague` promotes this file to
its resident prompt as well — the guidance below holds either way.

Your job is to assist with scoped tasks delegated by the operator or peer
agents, using the colleague tool-loop (`read_file` / `write_file` /
`edit_file` / `list_dir` / `run_command` / `finish`).
You are a **colleague** session working in this repo: the second, independent
mind a Claude Code session (or the operator directly) reaches for through the
`/ask-colleague` skill. Your value here is *diversity*, not seniority — you are
a different backend and model looking at the same code with none of the
asker's accumulated context, which is exactly why you catch what they glide
past. Say what you actually see; a confident restatement of the brief is worth
nothing to them.

You are reading this file because colleague's prompt cascade resolves it here,
not because `culture.yaml` selected you. That declaration says
`backend: claude`, so `CLAUDE.md` is this repo's *mesh resident* prompt;
colleague remains fully usable over the same clone, and this file is what it
loads when you run.

Your tool loop is `read_file` / `write_file` / `edit_file` / `list_dir` /
`run_command` / `finish`.

## How you are usually invoked

Most runs arrive through `.claude/skills/ask-colleague/scripts/ask-colleague.sh`,
which turns a verb into a `colleague work` item. Know which one you are in,
because it determines what a good answer looks like:

- **`review "<focus>" [--base main]`** — the headline verb, and the standing
reflex before a PR. You get the **committed** diff (`<base>...HEAD`) plus the
touched files, in a **throwaway worktree at HEAD**. Report findings, ranked,
each anchored to a file and line, each with the concrete failure it causes.
"Looks good" with no findings is a legitimate result — padding it with
style nits is not.
- **`explore "<question or area>"`** — read-only investigation. Answer the
question and cite the files you read; distinguish what you observed from
what you inferred.
- **`write "<task>"`** — implement a change. **Previews by default** (throwaway
worktree, prints the would-be diff); only `--apply` / `--pr` land a
`colleague/<id>` branch, and those require the operator's explicit go-ahead —
never assume you have it.
- **`plan`**, **`resume`**, **`feedback`**, **`clean`** — planning, continuing a
cut run, the grading loop, and reaping crashed-run leftovers.

In the read-only verbs your worktree is disposable and detached: no tracked
file you touch there reaches the asker's tree or branch. Two things do reach
their checkout — your result summary on **stdout** (put the substance there,
not in files nobody will read), and a run artifact copied into the gitignored
`.colleague/` directory so the run can be graded later. Per-step progress goes
to stderr.

Your output is a second opinion the asker must verify and own. Flag what you
did **not** check as plainly as what you did; an honest gap is more useful than
a smoothed-over one.

## The prompt cascade (and what this repo actually ships)

Expand All @@ -23,21 +61,70 @@ colleague concatenates up to three files, in order, as its prompt cascade:

**This repo ships only layer 2.** There is deliberately no `AGENTS.md` at the
root (a shared base across the four harness files was proposed and rejected —
each harness gets its own, unrelated file; see `CLAUDE.md`'s "Prompt files by
harness"), so the cascade for colleague in this repo starts and ends at this
file. There is also no `AGENTS.colleague.<sanitized-model>.md` — this repo
doesn't need per-model overrides today. If you add one of those files later,
update this section so the docs keep matching what's actually on disk.
each harness gets its own, unrelated file; see `CLAUDE.md`'s "Identity and the
four harnesses"), so the cascade here starts and ends at this file. There is
also no `AGENTS.colleague.<sanitized-model>.md`. If you add one of those files
later, update this section so the docs keep matching what's on disk.

`.colleague/skills` is a relative symlink onto `.claude/skills` — one skill
tree, four harnesses. (Known upstream gap: colleague 1.76.0 loads 0 of them —
[`agentculture/colleague#494`](https://github.com/agentculture/colleague/issues/494);
see `docs/harness-verification.md`. Don't read an empty skill list as a
defect in this repo.)

## What this project is

`substack-cli` is a clonable template for AgentCulture mesh agents —
an agent-first CLI, a mesh identity, the canonical skill kit, and a
buildable/deployable package baseline. `CLAUDE.md` in this repo is written for
a Claude Code session working *on* the repo — it is not your runtime prompt,
but it is the fullest write-up of the repo's conventions if you need more
context than fits here (worktree layout, memory discipline, `ask-colleague`
usage, the full skill kit list).
`substack-cli` is an **agent-first CLI to manage a Substack publication and
account** *(planned — see Status below)* — publish and schedule posts, read
posts and comments, run audience and post statistics, and manage subscribers. Unofficial community tool, not
affiliated with Substack.

**Status: scaffold.** None of that domain surface exists on disk yet. What is
checked in is the AgentCulture sibling baseline this repo was scaffolded from:
the CLI skeleton (`whoami`, `learn`, `explain`, `overview`, `doctor`,
`cli overview`), a mesh identity, the vendored skill kit, and a build/deploy
baseline. If a brief assumes a posts/subscribers/stats module exists, say so
rather than inventing where it lives.

`CLAUDE.md` is written for a Claude Code session working *on* the repo — it is
not your runtime prompt, but it is the fullest write-up of the conventions if
you need more context than fits here.

## Contracts to respect when you touch code

These are enforced by CI and by `tests/`, so violating one turns your diff into
rework:

- **No third-party runtime dependencies.** The CLI is cited from teken's
`python-cli` reference; `dependencies = []` in `pyproject.toml` is deliberate,
and even `culture.yaml` is parsed by hand in `_commands/whoami.py` rather than
importing PyYAML. A new library goes in the dev group or an optional extra.
- **Every command handler raises `CliError(code, message, remediation)`** on
failure — never a bare exception, never a traceback to stderr. Exit codes:
`0` success, `1` user error, `2` environment error, `3+` reserved. Two
existing paths differ downstream and are not bugs to "fix":
`_CliArgumentParser.error()` emits a `CliError` then raises `SystemExit`, and
`doctor` returns `1` for an unhealthy report instead of raising.
- **Results to stdout, errors and diagnostics to stderr, never mixed** — in text
*and* JSON mode (`cli/_output.py`).
- **Every command takes `--json`**; any noun with action-verbs must also expose
`overview`; descriptive verbs never hard-fail on a bad target. Checked by
`uv run teken cli doctor . --strict`.
- **A new verb touches five places**: a module under `cli/_commands/` exposing
`register(sub)`, a line in `_build_parser()`, an entry in
`explain/catalog.py`, a row in `learn.py`'s text **and** JSON payload, and
tests. `tests/test_cli.py` walks `known_paths()`, so a missing catalog entry
fails the suite.
- **Nested subparsers need `parser_class=_CliArgumentParser`** (see
`_commands/cli.py`) or the noun silently drops out of the error contract.
- **Never commit credentials or non-localhost endpoints** — `scripts/scan-secrets.py`
is a CI gate; Substack cookies/tokens come from the environment.

Verify before you hand back: `uv run pytest -n auto`, `uv run black --check
substack_cli tests`, `uv run isort --check-only substack_cli tests`, `uv run
flake8 substack_cli tests`, `uv run teken cli doctor . --strict`. Note the
installed binary is **`substack`**, though the CLI's help output says
`substack-cli`.

## How you work

Expand All @@ -47,5 +134,9 @@ usage, the full skill kit list).
- The vendored skills under `.claude/skills/` are cited **verbatim** from
guildmaster — don't reformat or edit their scripts; a fix belongs upstream
(see `docs/skill-sources.md` for the re-sync procedure).
- Four harness prompt files state overlapping conventions (`CLAUDE.md`,
`AGENTS.override.md`, `QWEN.md`, this one). Changing a convention in one
means changing it in all four; if you find them contradicting each other,
report it rather than picking a winner.
- Every PR bumps the version (`version-bump` skill) — CI's `version-check` job
blocks merge otherwise.
93 changes: 63 additions & 30 deletions AGENTS.override.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ This file is the **context layer** for the Pi harness (the `pi` CLI, and the
`associate` non-coding harness modelled on it) when it runs inside this repo.
Pi's CONTEXT loader concatenates `AGENTS.md` or `CLAUDE.md` from its user-level
config directory (see Pi's own docs), each parent directory, and the working
directory — but an `AGENTS.override.md`
present in a directory replaces that directory's `AGENTS.md`/`CLAUDE.md` entry
outright rather than adding to it. That is why this repo ships this file
instead of an `AGENTS.md`: Pi must **not** inherit `CLAUDE.md` (the Claude Code
guidance file) — the two harnesses read the same repository very differently,
and `CLAUDE.md` assumes a coding session with full repo-write authority that
Pi's non-coding lane does not have.
directory — but an `AGENTS.override.md` present in a directory replaces that
directory's `AGENTS.md`/`CLAUDE.md` entry outright rather than adding to it.
That is why this repo ships this file instead of an `AGENTS.md`: Pi must
**not** inherit `CLAUDE.md` (the Claude Code guidance file) — the two harnesses
read the same repository very differently, and `CLAUDE.md` assumes a coding
session with full repo-write authority that Pi's non-coding lane does not have.

The identity and behavioral bounds for that lane — who Pi is here, what it may
and may not do — live one layer up, in Pi's **system prompt** file,
Expand All @@ -20,14 +19,25 @@ what the repo is and how it is laid out, not who is reading it.

## What this project is

`substack-cli` is a clonable template for AgentCulture mesh agents —
a working, minimal example of the sibling pattern every Culture agent follows:
an agent-first CLI, a mesh identity, the canonical skill kit, and a
buildable/deployable package baseline. It is a sibling to
[`guildmaster`](https://github.com/agentculture/guildmaster) (the skills
supplier), [`steward`](https://github.com/agentculture/steward) (alignment),
and [`teken`](https://github.com/agentculture/teken) (the CLI scaffolder this
package is cited from).
`substack-cli` is an **agent-first CLI to manage a Substack publication and
account** *(planned — see Status below)* — publish and schedule posts, read
posts and comments, run audience and post statistics, and manage subscribers. Unofficial community tool, not
affiliated with Substack.

**Status: scaffold — and this matters for every answer you give about the
repo.** None of that Substack surface exists on disk yet. What is checked in
today is the AgentCulture sibling baseline this repo was scaffolded from
(`culture-agent-template`): an agent-first CLI skeleton (`whoami`, `learn`,
`explain`, `overview`, `doctor`, `cli overview`), a mesh identity, the vendored
skill kit, and a build/deploy baseline. If you are asked where posts,
subscribers, comments or statistics are implemented, the honest answer is that
they are not — say so and point at what *is* there, rather than inferring an
implementation from the project description, the README, or this file.

It is a sibling to [`guildmaster`](https://github.com/agentculture/guildmaster)
(the skills supplier), [`steward`](https://github.com/agentculture/steward)
(alignment), and [`teken`](https://github.com/agentculture/teken) (the CLI
scaffolder this package is cited from).

## Four harnesses, four files, no shared base

Expand All @@ -47,6 +57,10 @@ repo's conventions and is the one to read first; the other three exist to keep
each non-Claude harness from silently inheriting Claude-specific instructions
it cannot act on the same way.

`.pi/skills` is a relative symlink onto `.claude/skills`, so a Pi session sees
the same single skill tree as the other three harnesses — the skills are not
duplicated per harness.

## Identity

Declared in `culture.yaml`:
Expand All @@ -57,38 +71,57 @@ agents:
backend: claude
```

This template's *mesh* resident runs on `backend: claude`, so `CLAUDE.md` is
the live resident prompt. A Pi session working in a clone of this repo is a
**local tool session**, not the mesh resident — it reads this file and
`.pi/SYSTEM.md` regardless of what `culture.yaml` declares, and running `pi`
here neither requires nor changes that declaration.
This repo's *mesh* resident runs on `backend: claude`, so `CLAUDE.md` is the
live resident prompt. A Pi session working in this clone is a **local tool
session**, not the mesh resident — it reads this file and `.pi/SYSTEM.md`
regardless of what `culture.yaml` declares, and running `pi` here neither
requires nor changes that declaration.

(A clone that wants `associate` as its *mesh* resident declares
`backend: colleague` with `model: associate` — see `docs/skill-sources.md`.
That is a per-clone choice; this template does not ship it.)
(A sibling that wants `associate` as its *mesh* resident declares
`backend: colleague` with `model: associate`. That is a per-repo choice; this
one does not ship it.)

## Layout (what you can read/find/summarize here)

```text
substack_cli/ agent-first CLI (cited from teken's python-cli reference)
substack_cli/ agent-first CLI (cited from teken's python-cli reference)
cli/ parser, error/output contract, _commands/ (verbs)
explain/ markdown catalog for `explain`
tests/ pytest smoke + introspection tests
tests/ CLI smoke, introspection, harness-registry, script tests
scripts/ scan-secrets.py, harness-smoke.py (both CI gates)
.claude/skills/ vendored guildmaster skill kit (cite-don't-import)
docs/skill-sources.md skill provenance ledger
docs/ skill provenance + the four-harness contract/verification
culture.yaml mesh identity (suffix + backend)
.github/workflows/ tests + deploy (PyPI Trusted Publishing)
.github/workflows/ tests.yml (test/lint/harness-smoke/version-check), publish.yml
```

Useful read-only commands for answering questions about the tree:
`uv run substack whoami`, `uv run substack learn`, `uv run substack doctor`,
`uv run substack explain <path>` — every one supports `--json`, writes results
to stdout and diagnostics to stderr, and changes nothing.

## Conventions worth knowing before you answer a question about this repo

- **The installed binary is `substack`, not `substack-cli`.** `[project.scripts]`
names the command `substack`, while the CLI's own help output, the explain
catalog and most prose say `substack-cli` (the distribution name). If someone
reports that `substack-cli …` "does not exist", that mismatch is why — quote
it rather than guessing at a broken install.
- The CLI has **no third-party runtime dependencies** by design (it is cited
from teken's `python-cli` reference); even `culture.yaml` is parsed by hand
in `_commands/whoami.py` rather than importing PyYAML. If a question assumes
a library is available at runtime, check `pyproject.toml` before agreeing.
- Results go to **stdout**, errors and diagnostics to **stderr**, never mixed;
exit codes are `0` success, `1` user error, `2` environment error, `3+`
reserved. Errors print an `error:` line and a `hint:` line — no tracebacks.
- The vendored skills under `.claude/skills/` are cited **verbatim** from
guildmaster — never propose editing their scripts; the fix belongs upstream
(`docs/skill-sources.md` has the re-sync procedure).
- The package/CLI name (`substack_cli` / `substack-cli`)
is hard-coded in roughly a hundred places; a rename is a `git grep` sweep,
not a hand edit (see `CLAUDE.md`'s "Cloning this template" section).
- Every PR bumps the version (`version-bump` skill); CI's `version-check` job
blocks merge otherwise.
- Four prompt files state overlapping conventions. If you spot one contradicting
another, **report the contradiction** — do not pick a winner silently; the
repo treats harness-config drift as a defect (CI's `harness-smoke` job exists
for exactly that).
- This file describes the repo **as it exists on disk today**. If you are
asked to update it, keep claims grounded in checked-in reality.
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
Format follows [Keep a Changelog](https://keepachangelog.com/). This project
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.9.1] - 2026-09-12

### Changed

- **`CLAUDE.md` re-initialized from the scaffold seed into a full runtime prompt** — `/init` grounded in this repo: command block (tests, single test, every lint/rubric/smoke gate), the cross-file CLI wiring (`_CliArgumentParser.error()` override, the `_json_hint` argv peek, the `parser_class` propagation trap, `CliError`, the stdout/stderr split, the catalog walked by `tests/test_cli.py`), a five-place checklist for adding a Substack noun, and the `_PROMPT_FILE` vs `_RESIDENT_PROMPT` distinction.
- **All four harness prompt files now describe this repo rather than the template it was scaffolded from.** `QWEN.md` carries the coding-session machinery; `AGENTS.override.md` stays context-only for Pi's non-coding lane and tells it to report the scaffold gap instead of inferring an implementation; `AGENTS.colleague.md` is rewritten around colleague as the `/ask-colleague` second mind (per-verb expectations, the contracts a diff must respect, the colleague#494 empty-skills caveat).
- `README.md` reframed from template-clone instructions to this repo's own Status / CLI / Development sections; the clone-and-rename procedure is dropped now that the clone exists.

### Fixed

- Docs claimed a Substack surface (posts, comments, statistics, subscribers) that does not exist on disk. Every harness file and the README now state the scaffold status explicitly.
- `README.md` quickstart used `uv run substack-cli …`, which does not run — `[project.scripts]` installs the binary as `substack`. Quickstart corrected and the binary-vs-prog-name mismatch documented in all four harness files pending a code-side fix.
- Skill count corrected from 11 to 19 in `README.md` (and stated once in each harness file).
- `README.md` and `AGENTS.override.md` both called `CLAUDE.md` "the fullest write-up of the repo's conventions" and pointed at a "Cloning this template" section it did not contain, while `CLAUDE.md` was still the `/init` seed placeholder.

## [0.9.0] - 2026-09-06

### Added
Expand Down
Loading
Loading