You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
config-declared page kinds (person, decision, system, plus anything a kb adds under page_kinds in config.yaml — see #234) carry required frontmatter fields, an optional frontmatter schema, and a required_citations flag. today an author has to know those fields by heart and hand-write the --meta key=value pairs on vouch propose-page, or discover the gaps only when propose_page rejects the proposal. vouch schema list already surfaces per-kind requirements via load_page_kind_registry(store).resolve(name), but nothing turns that into a filled starting point.
vouch new <kind> closes that gap: it reads the registry for <kind>, stubs (or interactively prompts for) every required field, and emits a proposal through the normal review gate — so authors get a correctly-shaped draft instead of a frontmatter guessing game, and the reviewer still sees exactly one pending proposal to approve or reject.
proposed surface
vouch new <kind> --title <t> — resolve <kind> against load_page_kind_registry(store); for each required field returned by .resolve() (which yields (required_fields, frontmatter_schema, required_citations)), stub an empty value into the frontmatter dict (or prompt when --interactive).
flags:
--title <t> (required for page kinds).
--field key=value (repeatable) — pre-fill a required/optional field; parsed as yaml, the same way _parse_meta handles --meta on propose-page.
--interactive / -i — prompt for each unfilled required field at the terminal; default off so it stays scriptable.
--dry-run — print the assembled draft (title, resolved kind, frontmatter, missing-field list) without creating a proposal; passes through to propose_page(..., dry_run=True).
--json — emit the resulting proposal id (or the dry-run draft) machine-readably.
entity kinds route to propose_entity instead of propose_page. entity kinds are the EntityType members (person, project, repo, company, concept, decision, workflow); vouch new person --name <n> stubs the entity shape.
dispatch and ambiguity: some names collide (decision and project are both an EntityType member and a possible page kind). resolve deterministically — a name present in the page-kind registry scaffolds a page; --entity forces the entity path; a name that is only an EntityType scaffolds an entity. an unknown name fails clearly.
config: no new config surface. the field set is derived entirely from the existing page_kinds registry; a required_citations kind gets a stubbed-but-empty --claim/--source reminder in the draft rather than a silent pass.
no new kb.* method. the scaffold is a client-side convenience that composes the existing propose_page / propose_entity proposal calls, so it needs no server/jsonl/capabilities registration — just the cli command in src/vouch/cli.py and a test at tests/test_new_scaffold.py (or tests/test_cli.py if that is where the propose-page cli tests live).
review gate & scope
the scaffold only produces a pending proposal. it calls propose_page(store, ..., proposed_by=_whoami()) (or propose_entity) exactly as the existing propose-page / propose-entity commands do — the same path that already runs the page_kinds validation and dangling-reference checks. a scaffolded draft is never written as an approved page or entity; a human still runs vouch approve <id> (kb.approve) to land it. filling required fields does not weaken validation: propose_page re-validates the kind, so a scaffold that leaves a required field empty is proposable but flagged the same way any other proposal is.
stays local-first and pure: field resolution reads the registry only; no business logic moves into storage.py; the command does string assembly plus one existing proposals.* call. --dry-run reuses propose_page's existing dry_run flag rather than a parallel write path.
acceptance criteria
vouch new decision --title "pick X" creates a pending page proposal whose frontmatter stubs every required field for the decision page kind, resolved from load_page_kind_registry(store).
vouch new person --name "alice-example" routes to propose_entity and creates a pending entity proposal.
a name present in the page-kind registry scaffolds a page; --entity forces the entity path; the collision cases (decision, project) resolve to exactly one target with no silent guess.
--field key=value pre-fills a field, parsed as yaml (so --field attendees=[a, b] arrives as a list), matching the --meta / _parse_meta behavior on propose-page.
--interactive prompts only for required fields left unfilled; non-interactive runs never block on a prompt.
--dry-run prints the assembled draft and its missing-required-field list and creates no proposal (propose_page(..., dry_run=True)).
the created artifact is a pending proposal only: it shows up in vouch pending, and does not become an approved page or entity until a human vouch approves it.
an unknown <kind> fails clearly, listing known kinds from registry.known(), instead of stubbing an invalid page.
required_citations kinds surface a citation reminder in the draft rather than silently proposing an uncited page.
test under tests/ covers page-kind scaffold, entity scaffold, dry-run (no write), collision dispatch, and unknown-kind error.
adjacent: #234 introduced config-declared typed page kinds and the vouch schema inspection commands; this issue does not add or change kinds — it consumes the existing registry to scaffold a proposal for one. distinct from vouch propose-page, which takes fully hand-authored --meta and does no field discovery.
config-declared page kinds (
person,decision,system, plus anything a kb adds underpage_kindsin config.yaml — see #234) carry required frontmatter fields, an optional frontmatter schema, and arequired_citationsflag. today an author has to know those fields by heart and hand-write the--meta key=valuepairs onvouch propose-page, or discover the gaps only whenpropose_pagerejects the proposal.vouch schema listalready surfaces per-kind requirements viaload_page_kind_registry(store).resolve(name), but nothing turns that into a filled starting point.vouch new <kind>closes that gap: it reads the registry for<kind>, stubs (or interactively prompts for) every required field, and emits a proposal through the normal review gate — so authors get a correctly-shaped draft instead of a frontmatter guessing game, and the reviewer still sees exactly one pending proposal to approve or reject.proposed surface
vouch new <kind> --title <t>— resolve<kind>againstload_page_kind_registry(store); for each required field returned by.resolve()(which yields(required_fields, frontmatter_schema, required_citations)), stub an empty value into the frontmatter dict (or prompt when--interactive).--title <t>(required for page kinds).--field key=value(repeatable) — pre-fill a required/optional field; parsed as yaml, the same way_parse_metahandles--metaonpropose-page.--interactive / -i— prompt for each unfilled required field at the terminal; default off so it stays scriptable.--body <text>/--body -— page body, mirroringpropose-page(-reads stdin).--dry-run— print the assembled draft (title, resolved kind, frontmatter, missing-field list) without creating a proposal; passes through topropose_page(..., dry_run=True).--json— emit the resulting proposal id (or the dry-run draft) machine-readably.propose_entityinstead ofpropose_page. entity kinds are theEntityTypemembers (person,project,repo,company,concept,decision,workflow);vouch new person --name <n>stubs the entity shape.decisionandprojectare both anEntityTypemember and a possible page kind). resolve deterministically — a name present in the page-kind registry scaffolds a page;--entityforces the entity path; a name that is only anEntityTypescaffolds an entity. an unknown name fails clearly.page_kindsregistry; arequired_citationskind gets a stubbed-but-empty--claim/--sourcereminder in the draft rather than a silent pass.no new
kb.*method. the scaffold is a client-side convenience that composes the existingpropose_page/propose_entityproposal calls, so it needs no server/jsonl/capabilities registration — just the cli command insrc/vouch/cli.pyand a test attests/test_new_scaffold.py(ortests/test_cli.pyif that is where the propose-page cli tests live).review gate & scope
the scaffold only produces a pending proposal. it calls
propose_page(store, ..., proposed_by=_whoami())(orpropose_entity) exactly as the existingpropose-page/propose-entitycommands do — the same path that already runs thepage_kindsvalidation and dangling-reference checks. a scaffolded draft is never written as an approved page or entity; a human still runsvouch approve <id>(kb.approve) to land it. filling required fields does not weaken validation:propose_pagere-validates the kind, so a scaffold that leaves a required field empty is proposable but flagged the same way any other proposal is.stays local-first and pure: field resolution reads the registry only; no business logic moves into
storage.py; the command does string assembly plus one existingproposals.*call.--dry-runreusespropose_page's existingdry_runflag rather than a parallel write path.acceptance criteria
vouch new decision --title "pick X"creates a pending page proposal whose frontmatter stubs every required field for thedecisionpage kind, resolved fromload_page_kind_registry(store).vouch new person --name "alice-example"routes topropose_entityand creates a pending entity proposal.--entityforces the entity path; the collision cases (decision,project) resolve to exactly one target with no silent guess.--field key=valuepre-fills a field, parsed as yaml (so--field attendees=[a, b]arrives as a list), matching the--meta/_parse_metabehavior onpropose-page.--interactiveprompts only for required fields left unfilled; non-interactive runs never block on a prompt.--dry-runprints the assembled draft and its missing-required-field list and creates no proposal (propose_page(..., dry_run=True)).vouch pending, and does not become an approved page or entity until a humanvouch approves it.<kind>fails clearly, listing known kinds fromregistry.known(), instead of stubbing an invalid page.required_citationskinds surface a citation reminder in the draft rather than silently proposing an uncited page.tests/covers page-kind scaffold, entity scaffold, dry-run (no write), collision dispatch, and unknown-kind error.adjacent: #234 introduced config-declared typed page kinds and the
vouch schemainspection commands; this issue does not add or change kinds — it consumes the existing registry to scaffold a proposal for one. distinct fromvouch propose-page, which takes fully hand-authored--metaand does no field discovery.