steward-cli 0.1.2__tar.gz → 0.3.0__tar.gz

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.
Files changed (45) hide show
  1. steward_cli-0.3.0/.claude/skills/doc-test-alignment/SKILL.md +55 -0
  2. steward_cli-0.3.0/.claude/skills/doc-test-alignment/scripts/check.sh +24 -0
  3. {steward_cli-0.1.2 → steward_cli-0.3.0}/.markdownlint-cli2.yaml +2 -2
  4. steward_cli-0.3.0/CHANGELOG.md +106 -0
  5. {steward_cli-0.1.2 → steward_cli-0.3.0}/CLAUDE.md +39 -1
  6. {steward_cli-0.1.2 → steward_cli-0.3.0}/PKG-INFO +2 -1
  7. steward_cli-0.3.0/docs/perfect-patient.md +35 -0
  8. steward_cli-0.3.0/docs/sibling-pattern.md +90 -0
  9. steward_cli-0.3.0/docs/skill-sources.md +43 -0
  10. {steward_cli-0.1.2 → steward_cli-0.3.0}/pyproject.toml +4 -2
  11. {steward_cli-0.1.2 → steward_cli-0.3.0}/steward/cli/__init__.py +2 -0
  12. steward_cli-0.3.0/steward/cli/_commands/_corpus.py +522 -0
  13. steward_cli-0.3.0/steward/cli/_commands/doctor.py +472 -0
  14. {steward_cli-0.1.2 → steward_cli-0.3.0}/tests/test_cli.py +3 -1
  15. steward_cli-0.3.0/tests/test_cli_doctor.py +91 -0
  16. steward_cli-0.3.0/tests/test_cli_doctor_siblings.py +186 -0
  17. steward_cli-0.3.0/tests/test_corpus.py +257 -0
  18. steward_cli-0.3.0/tests/test_skills_convention.py +106 -0
  19. {steward_cli-0.1.2 → steward_cli-0.3.0}/uv.lock +5 -1
  20. steward_cli-0.1.2/CHANGELOG.md +0 -53
  21. {steward_cli-0.1.2 → steward_cli-0.3.0}/.claude/skills/agent-config/SKILL.md +0 -0
  22. {steward_cli-0.1.2 → steward_cli-0.3.0}/.claude/skills/agent-config/scripts/show.sh +0 -0
  23. {steward_cli-0.1.2 → steward_cli-0.3.0}/.claude/skills/pr-review/SKILL.md +0 -0
  24. {steward_cli-0.1.2 → steward_cli-0.3.0}/.claude/skills/pr-review/scripts/portability-lint.sh +0 -0
  25. {steward_cli-0.1.2 → steward_cli-0.3.0}/.claude/skills/pr-review/scripts/pr-batch.sh +0 -0
  26. {steward_cli-0.1.2 → steward_cli-0.3.0}/.claude/skills/pr-review/scripts/pr-comments.sh +0 -0
  27. {steward_cli-0.1.2 → steward_cli-0.3.0}/.claude/skills/pr-review/scripts/pr-reply.sh +0 -0
  28. {steward_cli-0.1.2 → steward_cli-0.3.0}/.claude/skills/pr-review/scripts/pr-status.sh +0 -0
  29. {steward_cli-0.1.2 → steward_cli-0.3.0}/.claude/skills/pr-review/scripts/workflow.sh +0 -0
  30. {steward_cli-0.1.2 → steward_cli-0.3.0}/.claude/skills/version-bump/SKILL.md +0 -0
  31. {steward_cli-0.1.2 → steward_cli-0.3.0}/.claude/skills/version-bump/scripts/bump.py +0 -0
  32. {steward_cli-0.1.2 → steward_cli-0.3.0}/.claude/skills.local.yaml.example +0 -0
  33. {steward_cli-0.1.2 → steward_cli-0.3.0}/.flake8 +0 -0
  34. {steward_cli-0.1.2 → steward_cli-0.3.0}/.github/workflows/publish.yml +0 -0
  35. {steward_cli-0.1.2 → steward_cli-0.3.0}/.github/workflows/tests.yml +0 -0
  36. {steward_cli-0.1.2 → steward_cli-0.3.0}/.gitignore +0 -0
  37. {steward_cli-0.1.2 → steward_cli-0.3.0}/LICENSE +0 -0
  38. {steward_cli-0.1.2 → steward_cli-0.3.0}/README.md +0 -0
  39. {steward_cli-0.1.2 → steward_cli-0.3.0}/steward/__init__.py +0 -0
  40. {steward_cli-0.1.2 → steward_cli-0.3.0}/steward/__main__.py +0 -0
  41. {steward_cli-0.1.2 → steward_cli-0.3.0}/steward/cli/_commands/__init__.py +0 -0
  42. {steward_cli-0.1.2 → steward_cli-0.3.0}/steward/cli/_commands/show.py +0 -0
  43. {steward_cli-0.1.2 → steward_cli-0.3.0}/steward/cli/_errors.py +0 -0
  44. {steward_cli-0.1.2 → steward_cli-0.3.0}/steward/cli/_output.py +0 -0
  45. {steward_cli-0.1.2 → steward_cli-0.3.0}/tests/__init__.py +0 -0
@@ -0,0 +1,55 @@
1
+ ---
2
+ name: doc-test-alignment
3
+ description: >
4
+ Verify that committed docs (README.md, CLAUDE.md, SKILL.md descriptions) still
5
+ describe what the code and tests actually do. Use at the end of a plan, before
6
+ PR creation, or when the user says "check doc-test alignment", "verify docs",
7
+ or "do the docs still match the code". STUB — `scripts/check.sh` exits with a
8
+ not-yet-implemented error today; the contract for what it will do lives in
9
+ this file.
10
+ ---
11
+
12
+ # doc-test-alignment (stub)
13
+
14
+ This skill is a stub. The real workflow is intentionally not yet implemented —
15
+ the file exists so that `steward verify` can find it and so contributors who
16
+ land here know it is on the roadmap, not forgotten.
17
+
18
+ ## How to run
19
+
20
+ `scripts/check.sh` is the entry point. Today it prints a not-yet-implemented
21
+ notice and exits non-zero. When the workflow lands, the script will gate
22
+ PR-readiness on the alignment contract below; until then, treat any green
23
+ exit code from this script as a bug.
24
+
25
+ ## What it will check
26
+
27
+ The skill is the contract for four narrow alignments. README.md command
28
+ examples must still execute against the current checkout and produce output
29
+ that matches the surrounding prose. The "build/test/publish" command lines in
30
+ CLAUDE.md must do the same. For each `.claude/skills/<name>/`, the SKILL.md
31
+ `description` frontmatter must agree with what the scripts under
32
+ `scripts/` actually do — surfacing disagreements (e.g. SKILL.md claims the
33
+ skill bumps versions but `scripts/` has no bump script). And for each test,
34
+ the test name should still describe the assertions the test makes — flagging
35
+ drift where the name advertises a feature the assertions no longer touch.
36
+
37
+ ## Why it ships as a stub
38
+
39
+ Each of those four checks is independently non-trivial. Shipping a partial
40
+ implementation would either silently pass when it shouldn't, or false-positive
41
+ on intentional doc-vs-code differences. The right path is to land the checks
42
+ one at a time, with their own tests, behind a
43
+ `steward verify --check doc-test-alignment` flag. The parent verbs (`verify`,
44
+ `doctor`) are named in the "Roadmap" section of `CLAUDE.md`; the broader
45
+ sibling-pattern contract lives in `docs/sibling-pattern.md`.
46
+
47
+ ## What this stub guarantees today
48
+
49
+ - The skill directory exists, so `steward verify`'s skills-convention check
50
+ finds the standard layout (SKILL.md + `scripts/` with an entry-point).
51
+ - `scripts/check.sh` is the entry-point script, satisfying the steward skills
52
+ convention requirement that every skill ships an executable script.
53
+ - This `SKILL.md` is the contract for what the skill will do — when the
54
+ implementation lands, it must satisfy this description or the description
55
+ must move first.
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env bash
2
+ # doc-test-alignment skill — entry point.
3
+ #
4
+ # STUB: the real workflow is not implemented yet. This script exists so the
5
+ # steward skills convention is satisfied (every skill ships an executable
6
+ # entry-point script); when the real implementation lands here, it must
7
+ # satisfy the contract documented in ../SKILL.md.
8
+ #
9
+ # Exits 2 (EXIT_USER_ERROR-ish for "you asked for something that isn't
10
+ # wired up yet") so callers can tell the difference between "checks passed"
11
+ # (would be 0) and "stub".
12
+
13
+ set -euo pipefail
14
+
15
+ cat >&2 <<'EOF'
16
+ doc-test-alignment: not yet implemented.
17
+
18
+ This skill is a stub; the contract for what `check.sh` will assert lives in
19
+ .claude/skills/doc-test-alignment/SKILL.md. Until the implementation lands,
20
+ treat any green exit code from this script as a bug.
21
+
22
+ Roadmap: see CLAUDE.md ("Roadmap (CLI surface)") and docs/sibling-pattern.md.
23
+ EOF
24
+ exit 2
@@ -1,6 +1,6 @@
1
1
  # markdownlint-cli2 config for steward.
2
- # markdownlint-cli2 stops walking at the git root, so the user's global
3
- # ~/.markdownlint-cli2.yaml isn't picked up from inside the repo.
2
+ # markdownlint-cli2 stops walking at the git root, so a per-user global
3
+ # config in the home directory isn't picked up from inside the repo.
4
4
  # Mirrors the afi-cli / cfafi preset for workspace consistency.
5
5
 
6
6
  config:
@@ -0,0 +1,106 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ Format follows [Keep a Changelog](https://keepachangelog.com/). This project
6
+ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.3.0] - 2026-04-26
9
+
10
+ ### Added
11
+
12
+ - `steward doctor --scope siblings` walks every `culture.yaml` in the workspace, scores each declared agent against a corpus-derived baseline, writes per-target feedback into `<target>/docs/steward/steward-suggestions.md` (gated by a marker line so hand-written content there is preserved), and refreshes `docs/perfect-patient.md` in the steward checkout. Diagnostic-only — corpus mode never exits non-zero on per-agent drift.
13
+ - `docs/perfect-patient.md` — committed placeholder; populated on each `--scope siblings` run with required/recommended `culture.yaml` fields, the common skills baseline, common `CLAUDE.md` sections, and corpus stats.
14
+ - `steward/cli/_commands/_corpus.py` — pure helpers (`discover_agents`, `synthesize_baseline`, `render_perfect_patient`, `score_culture_yaml_shape`, `score_agent_against_baseline`, `write_repo_report`) used by `doctor --scope siblings`. Tested in isolation by `tests/test_corpus.py`.
15
+ - `tests/test_corpus.py` and `tests/test_cli_doctor_siblings.py` — unit + end-to-end coverage for corpus mode (discovery handles both `agents:` lists and flat root-level `suffix:` shapes; baseline classification by frequency; report writer is idempotent and preserves hand-written content; JSON output shape; empty-workspace diagnostic; --no-write-reports / --no-refresh-perfect-patient gates).
16
+
17
+ ### Changed
18
+
19
+ - **Renamed `steward verify` → `steward doctor`** (single-repo mode). Same checks (`portability`, `skills-convention`), same flags (`--json`, `--check`), same exit semantics (non-zero on findings). New flags: `--scope {self,siblings}` (default `self` is backward-compatible with `verify`), `--workspace-root`, `--no-write-reports`, `--no-refresh-perfect-patient`, `--perfect-patient-out`. No `verify` alias kept — this is a breaking CLI change.
20
+ - Added `pyyaml>=6.0` as the first runtime dependency. Required to parse sibling `culture.yaml` manifests in corpus mode; the existing `agent-config` skill already shells out to a Python+PyYAML one-liner, so the dep was implicit.
21
+ - `docs/sibling-pattern.md` and `CLAUDE.md` Roadmap section rewritten to describe `doctor`'s two scopes (self / siblings) and reposition the planned `--apply` repair handlers as the next layer.
22
+
23
+ ## [0.2.0] - 2026-04-26
24
+
25
+ ### Added
26
+
27
+ - `steward verify <path>` — read-only diagnosis of a sibling repo against the
28
+ AgentCulture sibling pattern. Two checks today: `portability` (runs steward's
29
+ own vendored `portability-lint.sh --all` with `cwd=<target>`, so the target
30
+ doesn't need to vendor it and `verify` only ever executes a known-trusted
31
+ script) and `skills-convention` (every `SKILL.md` has a sibling `scripts/`
32
+ directory and a matching frontmatter `name`). Aggregates findings across all
33
+ selected checks; human-readable findings go to stderr, `--json` puts the
34
+ structured findings list on stdout. `--check <name>` repeatable. Exits 1 if
35
+ any finding was reported.
36
+ - `docs/sibling-pattern.md` — single source of truth for the AgentCulture
37
+ sibling pattern (12 required artifacts, 5 machine-checkable invariants,
38
+ 5 deterministic repairs). Consumed by `steward verify`; will be consumed
39
+ by the future `steward doctor`.
40
+ - `docs/skill-sources.md` — per-skill upstream declarations and vendoring
41
+ policy so `doctor` can vendor deterministically.
42
+ - `.claude/skills/doc-test-alignment/` — stub skill describing the intended
43
+ doc/test alignment workflow. Implementation TBD.
44
+ - `tests/test_skills_convention.py` — repo-level invariants for steward's own
45
+ skills (every skill has SKILL.md + scripts/, frontmatter name matches dir,
46
+ no per-user/home-dir paths in skill scripts).
47
+ - `tests/test_cli_verify.py` — end-to-end tests for the new verb, including a
48
+ dogfood test that runs `steward verify` against steward itself.
49
+
50
+ ### Changed
51
+
52
+ - `CLAUDE.md` gains a "Roadmap (CLI surface)" section naming `verify` and
53
+ `doctor` as the next two verbs.
54
+ - `.markdownlint-cli2.yaml` header comment reworded to avoid tripping the
55
+ portability lint with its own self-reference (caught by the new
56
+ `tests/test_cli_verify.py` dogfood test on first run).
57
+ - `tests/test_cli.py` help-output assertion loosened to match individual
58
+ verb names instead of the literal `{show}` group, so adding verbs doesn't
59
+ break it.
60
+
61
+ ## [0.1.2] - 2026-04-26
62
+
63
+ ### Added
64
+
65
+ - `.markdownlint-cli2.yaml` at repo root mirroring afi-cli/cfafi (3143024675).
66
+ - `lint` job in tests.yml running black --check, isort --check, flake8, bandit -c pyproject.toml, and markdownlint-cli2 (3143024677).
67
+ - `.flake8` config so flake8 honors the 100-char line length and ignores E203/W503 (matches black).
68
+
69
+ ### Changed
70
+
71
+ - `steward show` walk-up now stops at the git repo boundary so the script is only ever resolved within the user's current checkout (3143024681; eliminates the path-injection risk).
72
+ - `bump.py` changelog formatter emits single blank lines between elements (markdownlint MD012 compliant). Past triple-newlines in the 0.1.1 entry cleaned up.
73
+ - Tightened the `version-bump` SKILL.md: dropped the numbered Workflow section, replaced with short prose pointing to the script (3143024680).
74
+ - Replaced the inline `# noqa: S603 - explanation` syntax in show.py with a separate explanatory comment block above and a bare `# noqa: S603` (SonarCloud python:S7632).
75
+
76
+ ### Fixed
77
+
78
+ - CLAUDE.md: code-block fence now `text`-tagged (markdownlint MD040).
79
+
80
+ ## [0.1.1] - 2026-04-26
81
+
82
+ ### Changed
83
+
84
+ - test_python_m_steward_version uses sys.executable instead of literal python (3143024074).
85
+ - show.sh returns exit 2 for user errors (unknown suffix) and exit 1 for env errors (missing manifest, missing PyYAML); the steward CLI maps these to USER_ERROR/ENV_ERROR respectively (3143024081).
86
+
87
+ ### Fixed
88
+
89
+ - bump.py docstring no longer overstates what gets updated; the `__init__.py` rewrite is conditional and is a no-op for steward (3143024085).
90
+
91
+ ## [0.1.0] - 2026-04-26
92
+
93
+ ### Added
94
+
95
+ - `pyproject.toml` (steward-cli) with hatchling backend, `steward = "steward.cli:main"` entry point, Python ≥3.12. Zero runtime dependencies.
96
+ - `steward/` package: `__init__.py` (importlib.metadata version lookup), `__main__.py` (`python -m steward`), `cli/` (argparse entry point modeled on afi-cli's pattern with structured `StewardError` plumbing).
97
+ - `steward show <target>` subcommand that wraps the `agent-config` skill's `show.sh`. Walks up from cwd to locate the script; fails cleanly with a remediation hint if not in a Steward checkout.
98
+ - `tests/test_cli.py` — pytest suite covering `--version`, no-args help, unknown-subcommand error path, the `show` happy path against this repo, and `show` outside a Steward checkout.
99
+ - `.github/workflows/tests.yml` — pytest on every PR + push to main, with a `version-check` job that fails if `pyproject.toml` version isn't bumped (mirrors the cfafi convention; allows the initial scaffold via the "no main version yet" branch).
100
+ - `.github/workflows/publish.yml` — push to main publishes to PyPI via OIDC Trusted Publishing; PRs publish a `.dev<run_number>` to TestPyPI for smoke-testing. Fork PRs are skipped (no OIDC context).
101
+ - `.claude/skills/version-bump/` — vendored from afi-cli; bumps `pyproject.toml` and prepends a Keep-a-Changelog entry.
102
+
103
+ ### Changed
104
+
105
+ - `CLAUDE.md` — drop the "greenfield" framing, document the build/test/publish convention, and replace "Conventions to apply when scaffolding" with "Conventions in use".
106
+ - `README.md` — add Install + Usage sections.
@@ -25,7 +25,9 @@ steward/ # Python package (pip install steward-cli)
25
25
  ├── _errors.py # StewardError + EXIT_USER_ERROR / EXIT_ENV_ERROR
26
26
  ├── _output.py # emit_result / emit_error / emit_diagnostic
27
27
  └── _commands/ # subcommand modules; each has register(sub) + handler
28
- └── show.py # `steward show <target>` → wraps agent-config skill
28
+ ├── show.py # `steward show <target>` → wraps agent-config skill
29
+ ├── doctor.py # `steward doctor` → single-repo or corpus diagnosis
30
+ └── _corpus.py # corpus helpers used by `doctor --scope siblings`
29
31
  tests/ # pytest suite
30
32
  .claude/skills/ # see "Skills convention" below
31
33
  .github/workflows/ # tests.yml + publish.yml (OIDC Trusted Publishing)
@@ -61,6 +63,42 @@ Per-machine paths (Culture server manifest location, sibling-project paths, etc.
61
63
 
62
64
  Steward is a "skills supplier" for the Culture mesh. When a skill stabilizes here, the next step is propagating it to sibling projects (`culture`, `daria`, etc.) — the all-backends rule applied to skills.
63
65
 
66
+ ## Roadmap (CLI surface)
67
+
68
+ The CLI ships two verbs today: `steward show` and `steward doctor`. Doctor
69
+ runs in two modes — single-repo diagnosis (the original "verify" flow,
70
+ folded into doctor) and corpus mode (the agent-iteration flow). The
71
+ `--apply` repair mode is the next layer on top.
72
+
73
+ - `steward doctor <path>` (default `--scope self`) — score a target repo
74
+ against `docs/sibling-pattern.md`. Aggregates findings across all
75
+ selected checks, then exits non-zero if any finding was reported.
76
+ Human-readable findings go to stderr; `--json` emits the structured
77
+ findings list to stdout. Today: `portability` (runs steward's own
78
+ vendored `.claude/skills/pr-review/scripts/portability-lint.sh` against
79
+ the target, so the target doesn't need to vendor it) and
80
+ `skills-convention` (every `SKILL.md` has a sibling `scripts/`
81
+ entry-point and matching frontmatter `name`).
82
+ - `steward doctor --scope siblings` — walks every `culture.yaml` in the
83
+ workspace (`<workspace-root>/*/culture.yaml`, sibling-only by default),
84
+ tallies field/skill/CLAUDE.md-section frequency across the corpus to
85
+ synthesize `docs/perfect-patient.md`, scores every declared agent
86
+ against that baseline, and writes per-target feedback into
87
+ `<target>/docs/steward/steward-suggestions.md` (gated by a marker line
88
+ so hand-written content in that path is preserved). Diagnostic-only —
89
+ exits 0 even when individual agents drift from the baseline; that is
90
+ reported in the per-target file rather than as a CLI failure.
91
+ - `steward doctor --apply` *(planned)* — repair what diagnosis flagged,
92
+ where the repair is unambiguous (missing `scripts/` directory, missing
93
+ `.markdownlint-cli2.yaml`, missing `.claude/skills.local.yaml.example`,
94
+ etc.). Larger emissions (CLI scaffold) land later as additional repair
95
+ handlers, eventually consuming `../afi-cli/afi/cite/_engine.py` rather
96
+ than re-implementing it.
97
+
98
+ Per-skill upstreams (which repo owns the canonical copy of `version-bump`,
99
+ `pr-review`, etc.) are recorded in `docs/skill-sources.md` so `doctor` can
100
+ vendor deterministically.
101
+
64
102
  ## Working with Culture from here
65
103
 
66
104
  Steward will need to read or write Culture artifacts (agent definitions, server configs, mesh links). Useful entry points:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: steward-cli
3
- Version: 0.1.2
3
+ Version: 0.3.0
4
4
  Summary: Steward — aligns and maintains resident agents across Culture projects.
5
5
  Project-URL: Homepage, https://github.com/agentculture/steward
6
6
  Project-URL: Issues, https://github.com/agentculture/steward/issues
@@ -13,6 +13,7 @@ Classifier: License :: OSI Approved :: MIT License
13
13
  Classifier: Programming Language :: Python :: 3.12
14
14
  Classifier: Topic :: Software Development
15
15
  Requires-Python: >=3.12
16
+ Requires-Dist: pyyaml>=6.0
16
17
  Description-Content-Type: text/markdown
17
18
 
18
19
  # steward
@@ -0,0 +1,35 @@
1
+ # Perfect patient
2
+
3
+ > This file is auto-generated by `steward doctor --scope siblings`. The
4
+ > committed copy is a placeholder; run the command locally to populate it
5
+ > with real corpus statistics from the `culture.yaml` files in your
6
+ > workspace.
7
+ >
8
+ > The baseline is descriptive, not prescriptive: it describes what a
9
+ > typical healthy agent looks like in the current corpus, so drift can
10
+ > be spotted. Edit by hand only if you intend to ratchet the bar —
11
+ > `steward doctor --scope siblings` overwrites this file.
12
+
13
+ ## Required `culture.yaml` fields
14
+
15
+ Populated on first `steward doctor --scope siblings` run.
16
+
17
+ ## Recommended `culture.yaml` fields
18
+
19
+ Populated on first `steward doctor --scope siblings` run.
20
+
21
+ ## Common skills baseline
22
+
23
+ Populated on first `steward doctor --scope siblings` run.
24
+
25
+ ## Recommended skills
26
+
27
+ Populated on first `steward doctor --scope siblings` run.
28
+
29
+ ## Common `CLAUDE.md` sections
30
+
31
+ Populated on first `steward doctor --scope siblings` run.
32
+
33
+ ## Corpus stats
34
+
35
+ Populated on first `steward doctor --scope siblings` run.
@@ -0,0 +1,90 @@
1
+ # AgentCulture sibling pattern
2
+
3
+ The shape every AgentCulture sibling repo (`steward`, `cfafi`, `ghafi`, `daria`,
4
+ …) is expected to wear. This document is the single source of truth that
5
+ `steward doctor` consumes.
6
+
7
+ The companion file `sibling-pattern.json` (TBD; emit from this doc) is the
8
+ machine-readable form. Until it lands, the checks `doctor` runs are hard-coded
9
+ in `steward/cli/_commands/doctor.py`; this document remains the human-readable
10
+ contract that those hard-coded checks are expected to honor.
11
+
12
+ `steward doctor` runs in two modes:
13
+
14
+ - **`--scope self <target>`** (default) — the single-repo invariants below
15
+ (portability, skills-convention).
16
+ - **`--scope siblings`** — walks every `culture.yaml` in the workspace, scores
17
+ each declared agent against a corpus-derived baseline
18
+ (`docs/perfect-patient.md`, regenerated on each run), and writes a per-target
19
+ report into `<target>/docs/steward/steward-suggestions.md`.
20
+
21
+ ## Required artifacts
22
+
23
+ | # | Artifact | Path | Why |
24
+ |---|----------|------|-----|
25
+ | 1 | Toolchain | `pyproject.toml` (hatchling, Python ≥3.12, zero runtime deps where possible) | Uniform install/build/publish across the mesh. |
26
+ | 2 | Top-level package | `<pkg>/__init__.py`, `<pkg>/__main__.py` | `__version__` via `importlib.metadata`; `python -m <pkg>` works. |
27
+ | 3 | CLI scaffolding | `<pkg>/cli/__init__.py`, `cli/_errors.py`, `cli/_output.py`, `cli/_commands/` | The afi-cli pattern: structured errors, stdout/stderr split, `--json`. |
28
+ | 4 | Agent-first verbs | `cli/_commands/{learn,explain,whoami}.py` | `learn`/`explain` are the agent-affordance verbs; `whoami` is the smallest auth probe. |
29
+ | 5 | Mutation safety | Any write verb defaults to dry-run; `--apply` to commit | Agents call CLIs in loops; safe-by-default is mandatory. |
30
+ | 6 | Tests | `tests/test_cli_*.py`, pytest-xdist, coverage | CI gate; no untested verb ships. |
31
+ | 7 | CI | `.github/workflows/tests.yml`, `.github/workflows/publish.yml` | Tests + lint + version-check; PyPI/TestPyPI via Trusted Publishing. |
32
+ | 8 | Changelog | `CHANGELOG.md` (Keep-a-Changelog) | Bumped on every PR by the `version-bump` skill. |
33
+ | 9 | Skills | `.claude/skills/<name>/SKILL.md` + `scripts/` entry-point per skill | Convention: no external path deps, no per-user dotfile refs. |
34
+ | 10 | Per-machine config | `.claude/skills.local.yaml.example` (committed) + `.claude/skills.local.yaml` (git-ignored) | Skills read the local file, fall back to the example. |
35
+ | 11 | Lint configs | `.flake8`, `.markdownlint-cli2.yaml` (repo-local) | No reliance on per-user home-directory configs. |
36
+ | 12 | `CLAUDE.md` | Project shape, build/test/publish commands, conventions | What future Claude instances need that isn't discoverable from a 30-second `ls`. |
37
+
38
+ ## Invariants (machine-checkable)
39
+
40
+ The full set of invariants the AgentCulture sibling pattern asserts. The
41
+ **Status** column reflects what is wired into `steward doctor --scope self`
42
+ *today*; items marked `(planned)` are described here as the contract `doctor`
43
+ is expected to grow into.
44
+
45
+ - **portability** *(implemented as `--check portability`)* — no
46
+ `/home/<user>/...` paths in tracked files; no `~/.<dotfile>` config refs in
47
+ committed `.md`/`.yaml`/`.toml`/`.json`/`.jsonc` outside the carve-outs
48
+ (`~/.claude/skills/.../scripts/`, `~/.culture/`).
49
+ *Source:* `.claude/skills/pr-review/scripts/portability-lint.sh`.
50
+ - **skills-convention** *(implemented as `--check skills-convention`)* —
51
+ every `.claude/skills/<name>/SKILL.md` has a sibling
52
+ `.claude/skills/<name>/scripts/` directory, **and** the SKILL.md frontmatter
53
+ `name` equals the directory name. (The "every skill has at least one
54
+ entry-point script" invariant is satisfied by the directory existing today
55
+ to keep the check noise-free; tightening to "directory has ≥1 file" is
56
+ *(planned)*.)
57
+ - **changelog-format** *(planned)* — `CHANGELOG.md` has at least one
58
+ `## [x.y.z] - YYYY-MM-DD` heading.
59
+ - **lint-config-local** *(planned)* — `.markdownlint-cli2.yaml` exists at the
60
+ repo root (no reliance on per-user home configs).
61
+
62
+ ## Repairs (machine-fixable, run by `steward doctor`)
63
+
64
+ `steward doctor --apply` is **not yet implemented** (see `CLAUDE.md`'s
65
+ Roadmap section); the table below is the contract it will honor when it
66
+ lands. A repair is included only if it is **deterministic and idempotent**.
67
+ Where the right answer depends on judgement, `doctor` will report the gap
68
+ and stop.
69
+
70
+ | Invariant violated | Planned repair |
71
+ |--------------------|----------------|
72
+ | `.claude/skills/<name>/scripts/` missing | Create the empty directory + a stub entry-point script. |
73
+ | `.markdownlint-cli2.yaml` missing | Vendor steward's copy verbatim. |
74
+ | `.claude/skills.local.yaml.example` missing | Vendor a minimal template documenting the `culture_server_yaml` and `sibling_projects` keys. |
75
+ | `CHANGELOG.md` missing | Create a Keep-a-Changelog skeleton with one `## [Unreleased]` heading. |
76
+ | `SKILL.md` frontmatter `name` ≠ dir name | Reported only — too many false-positive renames to auto-correct. |
77
+ | Hard-coded `/home/...` path in tracked file | Reported only — fix requires understanding intent. |
78
+
79
+ ## Skill upstream policy
80
+
81
+ Per-skill upstream declarations live in `docs/skill-sources.md`. `doctor`
82
+ consults that file when vendoring a skill into a target sibling: each skill
83
+ has exactly one canonical source repo, and `doctor` copies from there.
84
+
85
+ ## Out of scope (for the pattern, not for steward)
86
+
87
+ - Pre-commit hooks (suggested but not required; siblings vary on this).
88
+ - Specific CI runners or Python versions beyond ≥3.12.
89
+ - Anything Culture-mesh-specific (server manifest, agent definitions) — that
90
+ belongs in `docs/` of the relevant Culture-side project, not in this pattern.
@@ -0,0 +1,43 @@
1
+ # Skill upstream sources
2
+
3
+ Each skill has exactly one canonical source repo. `steward doctor` consults
4
+ this file when vendoring a skill into a target sibling so the choice is
5
+ deterministic.
6
+
7
+ When a skill exists in multiple repos, the **upstream** column wins. Other
8
+ repos are downstream copies that may lag and should periodically re-sync from
9
+ upstream.
10
+
11
+ | Skill | Upstream | Downstream copies (known) | Notes |
12
+ |-------|----------|---------------------------|-------|
13
+ | `version-bump` | `steward` (`.claude/skills/version-bump/`) | `cfafi`, `afi-cli` | Pure Python, prepends Keep-a-Changelog entry; no per-repo customization needed. |
14
+ | `pr-review` | `steward` (`.claude/skills/pr-review/`) | `cfafi` (variant) | Steward owns the canonical workflow; downstream copies may add reviewer-specific wiring (Qodo/Copilot, etc.). |
15
+ | `agent-config` | `steward` (`.claude/skills/agent-config/`) | — | Steward-specific (resolves Culture agent suffixes); not portable as-is. |
16
+ | `doc-test-alignment` | `steward` (`.claude/skills/doc-test-alignment/`) | — | Stub; real implementation TBD. |
17
+ | `cfafi`, `cfafi-write` | `cfafi` (`.claude/skills/cfafi*/`) | — | CloudFlare-specific; not vendored elsewhere. |
18
+ | `poll` | `cfafi` (`.claude/skills/poll/`) | — | Background-reviewer subagent; candidate for promotion to `steward` if it stabilizes. |
19
+
20
+ ## Vendoring policy
21
+
22
+ - **Cite, don't import.** Skills are copied into the consuming repo, not
23
+ symlinked or installed as a dependency. Each consumer owns and may modify
24
+ their copy.
25
+ - **Re-sync explicitly.** When upstream changes, downstream copies do not
26
+ auto-update. `steward doctor --skill <name>` is the intended re-sync path
27
+ (TBD).
28
+ - **Diverge intentionally.** A downstream copy may diverge for repo-specific
29
+ reasons (e.g. `cfafi`'s `pr-review` adds CloudFlare-API reviewers). Record
30
+ the divergence in the downstream `SKILL.md`'s frontmatter `description`.
31
+
32
+ ## When a skill should be promoted upstream
33
+
34
+ A skill currently owned downstream (e.g. `poll` in `cfafi`) should be promoted
35
+ to `steward` when:
36
+
37
+ 1. At least one other sibling has copy-pasted it, OR
38
+ 2. Its scripts have no repo-specific assumptions (no hard-coded API
39
+ credentials, no per-product paths), AND
40
+ 3. Its `SKILL.md` describes a pattern (not a single product's workflow).
41
+
42
+ Promotion is a manual decision — `steward doctor` will not move skills
43
+ between repos.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "steward-cli"
3
- version = "0.1.2"
3
+ version = "0.3.0"
4
4
  description = "Steward — aligns and maintains resident agents across Culture projects."
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -13,7 +13,9 @@ classifiers = [
13
13
  "Topic :: Software Development",
14
14
  "Intended Audience :: Developers",
15
15
  ]
16
- dependencies = []
16
+ dependencies = [
17
+ "pyyaml>=6.0",
18
+ ]
17
19
 
18
20
  [project.urls]
19
21
  Homepage = "https://github.com/agentculture/steward"
@@ -32,6 +32,7 @@ class _StewardArgumentParser(argparse.ArgumentParser):
32
32
  def _build_parser() -> argparse.ArgumentParser:
33
33
  # Deferred import to avoid coupling the parser module to the command modules
34
34
  # at import time (matches afi-cli's pattern; cheap insurance).
35
+ from steward.cli._commands import doctor as _doctor_cmd
35
36
  from steward.cli._commands import show as _show_cmd
36
37
 
37
38
  parser = _StewardArgumentParser(
@@ -46,6 +47,7 @@ def _build_parser() -> argparse.ArgumentParser:
46
47
  sub = parser.add_subparsers(dest="command", parser_class=_StewardArgumentParser)
47
48
 
48
49
  _show_cmd.register(sub)
50
+ _doctor_cmd.register(sub)
49
51
 
50
52
  return parser
51
53