nerve config init-repo + config-repo setup runbook (13/13) - #216
Draft
alex-clickhouse wants to merge 1 commit into
Draft
nerve config init-repo + config-repo setup runbook (13/13)#216alex-clickhouse wants to merge 1 commit into
alex-clickhouse wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds “config repo” scaffolding + CI validation workflow, and introduces a zero-install validator entry point (python -m nerve.config_validate) designed to safely validate a checked-out config repo (portable-only, no machine overlays, no execution of repo code).
Changes:
- Add
nerve config init-repoandnerve.config_repo.scaffold_config_repo()to scaffold a config repo (workflow, gitignore, README, seeded settings). - Add a standalone validator entry point (
python -m nerve.config_validate) and unify output formatting viarender_result. - Update portable-only validation to suppress machine-local cron fallback, plus docs/tests/templates to match the new runbook + CI flow.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/test_config_validate.py | Adds portable-only cron fallback tests and coverage for the standalone validator entry point parity with the CLI. |
| tests/test_config_repo.py | New end-to-end tests for repo scaffolding, workflow correctness, pin “honesty”, and CI-safe execution. |
| nerve/templates/skills/nerve-workspace/SKILL.md | Documents operator-guided first-time config repo setup steps for the workspace skill. |
| nerve/templates/config-repo/validate-config.yml | Adds scaffolded GitHub Actions workflow: gitleaks scan + pinned-source validator run under PYTHONSAFEPATH. |
| nerve/templates/config-repo/README.md | Adds scaffolded README explaining repo layout and PR-based change flow. |
| nerve/templates/config-repo/gitignore | Adds scaffolded .gitignore for secrets/machine-local state (including backup secret members). |
| nerve/sync_service.py | Clarifies strict-keys behavior asymmetry between config-repo CI and instance sync validation. |
| nerve/config_validate.py | Implements portable-only cron suppression, adds shared rendering, and adds standalone argparse-based entry point. |
| nerve/config_repo.py | New module implementing idempotent scaffolding and validator ref pinning/notes. |
| nerve/config_pr.py | Documents intentional asymmetry between proposal validation and stricter CI validation. |
| nerve/cli.py | Updates config validate to use shared renderer and adds config init-repo command. |
| docs/config.md | Adds/updates full runbook for config repo setup and embeds the generated workflow verbatim. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
alex-clickhouse
force-pushed
the
config-refactor/13-repo-setup
branch
from
July 28, 2026 12:11
d2ab73d to
f66524f
Compare
alex-clickhouse
force-pushed
the
config-refactor/13-repo-setup
branch
from
July 28, 2026 12:36
f66524f to
d5e1d13
Compare
alex-clickhouse
force-pushed
the
config-refactor/13-repo-setup
branch
from
July 28, 2026 13:15
d5e1d13 to
1a105bb
Compare
alex-clickhouse
force-pushed
the
config-refactor/13-repo-setup
branch
from
July 28, 2026 14:23
1a105bb to
ddf95a2
Compare
alex-clickhouse
force-pushed
the
config-refactor/13-repo-setup
branch
from
July 28, 2026 14:54
ddf95a2 to
aa5620b
Compare
alex-clickhouse
force-pushed
the
config-refactor/13-repo-setup
branch
2 times, most recently
from
July 28, 2026 16:03
b6ab70d to
b5b9a84
Compare
alex-clickhouse
force-pushed
the
config-refactor/13-repo-setup
branch
from
July 28, 2026 16:20
b5b9a84 to
a16d310
Compare
alex-clickhouse
force-pushed
the
config-refactor/13-repo-setup
branch
2 times, most recently
from
July 29, 2026 08:29
6d2fa23 to
723bd92
Compare
alex-clickhouse
force-pushed
the
config-refactor/13-repo-setup
branch
from
July 29, 2026 09:18
723bd92 to
9026d50
Compare
alex-clickhouse
force-pushed
the
config-refactor/13-repo-setup
branch
from
July 29, 2026 09:31
9026d50 to
07c6a88
Compare
alex-clickhouse
force-pushed
the
config-refactor/13-repo-setup
branch
from
July 29, 2026 10:31
07c6a88 to
540bb6e
Compare
alex-clickhouse
force-pushed
the
config-refactor/13-repo-setup
branch
from
July 29, 2026 13:28
540bb6e to
e2915ea
Compare
alex-clickhouse
force-pushed
the
config-refactor/13-repo-setup
branch
2 times, most recently
from
July 30, 2026 08:25
90d495b to
15a4d05
Compare
alex-clickhouse
force-pushed
the
config-refactor/13-repo-setup
branch
from
July 30, 2026 08:55
15a4d05 to
61b660a
Compare
alex-clickhouse
force-pushed
the
config-refactor/13-repo-setup
branch
2 times, most recently
from
July 30, 2026 09:48
ff86bbd to
af2f6ee
Compare
alex-clickhouse
force-pushed
the
config-refactor/13-repo-setup
branch
from
July 30, 2026 10:06
af2f6ee to
cf17f09
Compare
alex-clickhouse
force-pushed
the
config-refactor/13-repo-setup
branch
from
July 30, 2026 10:47
cf17f09 to
97474c4
Compare
Scaffolds a config repo — the tracked layout, a .gitignore that does not leak the machine-local overlay, and a CI workflow — plus a runbook for the PR-to-merge-to-sync flow. The generated CI validates the bundle without installing nerve from the repo under review, so a pull request cannot execute its own unreviewed Python in order to be judged. It enforces what the docs promise rather than a weaker subset, and the documented job matches the one actually generated instead of an idealized version of it. --portable-only now means it. Cron resolution is file-aware and would otherwise fall back to the machine-local directory, handing a run that was asked to judge the shared bundle alone a file the bundle does not contain — so a typo in a local file could fail a config repo that has nothing wrong with it. Paths outside the tracked subtree are reported as declined rather than silently substituted. Co-Authored-By: Claude <noreply@anthropic.com>
alex-clickhouse
force-pushed
the
config-refactor/13-repo-setup
branch
from
July 30, 2026 12:44
97474c4 to
2010043
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
nerve config init-reposcaffolds a workspace into a shareable config repo — the CI validation workflow, a secrets-aware.gitignore, a README, and a seededconfig/settings.yaml— then prints the git/ghand instance-side steps it cannot do for you. Scaffolding is idempotent: an existing file is never overwritten, only reported as skipped, so re-running is safe (--dry-runshows the split without writing).The generated workflow gates every PR: a gitleaks scan first, then
nerve config validate --workspace . --portable-only --strict-keys. It needs no Actions secret to run.Alongside it:
--portable-onlynow covers cron as well as the machine-local config layers,docs/config.mdgains the full setup runbook with the generated workflow embedded verbatim, andpython -m nerve.config_validatebecomes a supported entry point for environments that cannot install nerve.Why
A config repo is only as good as the gate in front of it. Without CI, "reviewed configuration" means whatever a reviewer noticed by eye, and the failure modes that matter — a schedule the scheduler silently never runs, a secret committed in plaintext — are exactly the ones eyes miss.
Order matters. The secret scan runs before anything else is fetched: a validation failure that stopped the workflow early would leave a leaked credential unreported, and scanning before the install means it scans this repo and nothing else, so it needs no token of its own. Its image tag is pinned because an argument renamed in a later gitleaks would fail every config repo at once, with no pull request anywhere to explain it.
The validator tracks nerve's default branch rather than pinning to a revision. That is the safe direction for
--strict-keys: a validator at or ahead of the instance knows every key the instance reads, so an unknown key is a typo rather than version skew. It is also the direction the rest of this flow already leans —propose_config_changeand instance-side sync both leave an unrecognized key a warning, on the grounds that a key this nerve does not know is inert, and refusing an already-reviewed change over one would strand the instance on a stale config for a spelling the next upgrade may well know. Those asymmetries are now stated where they live rather than left to be rediscovered. A repo that would rather check against one release appends a ref to the install line; and where CI and an instance can still disagree, the--strict-keysfailure says so, so a config repo does not get blamed for a version difference.--portable-onlyhad a hole. Cron resolution is file-aware: a workspace carrying no jobs falls back to the machine-local~/.nerve/cronso an un-migrated install keeps working. That fallback is right at load time and wrong in a run asked to judge the shared bundle alone — it hands CI a file the repo does not contain, and a typo in that file fails a config repo with nothing wrong with it. It is the same substitution that skippingconfig.yaml/config.local.yamlprevents, one directory over. An explicitcron.jobs_filepointing outside the tracked subtree goes the same way.config/settings.yamlis part of the scaffold for a narrow reason: a repo with noconfig/at all fails its own workflow on the very first commit, because a portable-only run that opened no file underconfig/is an error there, not a pass. An instance's workspace already has the file and skips it.The standalone
python -m nerve.config_validatepath exists because everything the validator needs is the standard library plus PyYAML — a bundle can be checked by cloning nerve and settingPYTHONPATH, with no install and no resolution of nerve's full runtime. It shares the CLI's renderer, and the tests assert both directions of parity: identical output, and the same set of flags, since a flag the CLI has and this parser does not is a documented invocation this path cannot run.🤖 Generated with Claude Code