This file is the repository's stable agent constitution. Keep it small. Keep it durable. Keep it routing-focused. Volatile detail belongs in the referenced repo-owned artifacts, not here.
- You are authorized to plan, design, implement, test, document, and release ShellSyntaxTree v0.x.
- Default to the smallest safe change that advances the v0.1 acceptance
criteria in
SPEC.md§17. - Prefer explicit trade-offs over hidden complexity. Bias toward marking
inputs
DynamicSkip/IsUnparseableover guessing — this library feeds security gates.
SPEC.md— the locked v0.1 contract (public API, AST, grammar, verb tables, resolver, corpus rules). The contract.PROJECT_CONTEXT.md— what this is, who consumes it, scope discipline.TOOLING.md— what's available and how to access it.IMPLEMENTATION_PLAN.md— current NOW / NEXT / LATER work.- The relevant
dotnet-skills:*skill for the .NET concern at hand (seeTOOLING.mdrouting table).
When SPEC.md and any other artifact disagree, SPEC.md wins — fix
the other artifact in the same change.
Pick a MODE before acting. Each MODE has different signals, expected outputs, and definition-of-done.
Use when: implementing parser logic, lexer, resolver, verb tables,
AST records, options, or any production code under src/ShellSyntaxTree/,
plus the unit tests that exercise it.
Signals: changes under src/, non-corpus changes under tests/,
public-API surface changes (rare — requires bumping toward v0.2+).
Expected outputs:
- code under
src/ShellSyntaxTree/ - unit tests under
tests/ShellSyntaxTree.Tests/(NOT corpus JSON) dotnet buildanddotnet testboth pass locally- Public API surface matches
SPEC.md§2 exactly (any drift is a bug)
Definition of done: see Universal DoD below, plus: every behavior change is covered either by a unit test or a corpus entry.
Use when: authoring, sanitizing, or curating JSON entries under
tests/ShellSyntaxTree.Tests/Corpus/bash/*.json. The corpus is the
acceptance contract — corpus work is materially different from code work
(JSON shape, sanitization rules, PII audit).
Signals: changes under tests/.../Corpus/, references to dogfood
logs, requests like "add a case for chmod", "seed from logs".
Expected outputs:
- new or updated
*.jsoncorpus entries matching the SPEC §13 schema - entries cover the SPEC §13 category coverage targets
- if seeded from logs: every sanitization rule in SPEC §14 is applied, manually reviewed, and the entry is committed only after PII audit would pass on it
Definition of done: see Universal DoD, plus:
- the PII audit scan (regex rules from SPEC §14) finds zero hits
- every new entry parses to the declared
expectedAST when run throughBashParser(i.e., implementation must already cover it, OR this entry is intentionally a[Theory]failure that pins a NOW item in the implementation plan — note the link in the entry'snotesfield)
Use when: version bumps, RELEASE_NOTES.md updates, tagging, NuGet publish flow changes.
Signals: changes to RELEASE_NOTES.md, Directory.Build.props
VersionPrefix/VersionSuffix, .github/workflows/publish_nuget.yml,
or a request to "tag" / "ship" / "cut a release".
Expected outputs:
- semantic version that matches SPEC §15 progression rules
(
v0.1.xadditive,v0.2.0for first PowerShell parser, etc.) RELEASE_NOTES.mdupdated with the new section in the existing format- on tag push,
publish_nuget.ymlproduces a.nupkgmatchingVersionPrefix/VersionSuffixand pushes to nuget.org
Definition of done: see Universal DoD, plus:
- the tag triggers the publish workflow and the package appears on nuget.org
- for v0.1.0-alpha specifically: SPEC §17 acceptance #1-#8 all hold
Before adding code or a test, discover in this order:
- Is there a SPEC clause that already specifies the behavior? Implement to that. Do not invent shape that disagrees with the SPEC.
- Is there an existing corpus entry that pins the expected AST for this case? Make the implementation match the corpus.
- Is there a
dotnet-skills:*skill for the .NET concern? Open it; apply the parts that fit; note conflicts. - Is the construct in SPEC §1 / §18 non-goals? If yes, mark
IsUnparseableand stop.
If any of (1)-(4) conflict, fix the conflict before implementing.
- API surface is locked. Public types in
SPEC.md§2 do not change without a deliberate version bump. Internal types are free. - No silent fallbacks. If a token can't be safely classified, mark
DynamicSkip. If a construct can't be parsed, markIsUnparseable. Do not guess. Consumers can always relax — they can't un-execute a command we falsely classified safe. - No native dependencies. Multi-target
netstandard2.0andnet8.0; AOT-trim friendly. TreatWarningsAsErrors=trueis enforced repo-wide viaDirectory.Build.props. Don't suppress warnings to make a build pass — fix the cause.- No
Thread.Sleep/Task.Delayin tests to wait for conditions. Tests should be deterministic; the parser is synchronous. - Comments: skip noise, keep signal. Don't narrate code that
identifiers already explain. Do explain why a verb is in (or absent
from)
BashArity/FileVerbs, why a token marksDynamicSkip, why a fallback is or isn't safe in this context. - No stray sample apps, helper scripts, or "interesting" files. This
repo ships one library and its tests. If a helper is genuinely needed,
put it under
tests/or a clearly-scopedtools/folder and document it inTOOLING.md.
A change is done when all of these hold:
- behavior aligns with
SPEC.md(orSPEC.mdwas updated in the same change with explicit justification) dotnet build -c Releaseis cleandotnet test -c Releasepasses (unit + corpus)- copyright headers present on every new/modified
.csfile —pwsh ./scripts/Add-FileHeaders.ps1 -Verifyexits 0 (CI enforces this) - public API surface still matches SPEC §2 exactly
- corpus entries that touch the changed code path still pass
- if MODE=corpus: PII audit regex finds zero hits
- if MODE=release: tag-driven publish workflow succeeds end-to-end
IMPLEMENTATION_PLAN.mdis updated (item moved, completed, or parked) so the plan reflects reality
Run before declaring done:
dotnet tool restore
dotnet build -c Release
dotnet test -c Release
dotnet pack -c Release -o ./bin/nuget # only on release-shaped changesFor any code change that touches public API:
- diff
src/ShellSyntaxTree/headers againstSPEC.md§2 — they must match field-for-field.
For corpus changes:
- the PII audit test (a
[Fact]that scanstests/.../Corpus/bash/*.jsonfor the SPEC §14 forbidden patterns) must pass.
- If a workflow or correction repeats twice → extract or refine a skill or
add a row to
TOOLING.md. - If volatile project knowledge surfaces → put it in
PROJECT_CONTEXT.mdorIMPLEMENTATION_PLAN.md, not here. - This file should rarely change. Constitution edits are a deliberate act — they ripple to every future agent run.
- Compressing a referenced authority (SPEC, dotnet-skills, etc.) into a rule here is a retrieval operation, not a memory operation. If you can't write the rule without losing a distinction the source draws, drop the rule and link to the source instead.
# Restore and build everything
dotnet tool restore && dotnet restore && dotnet build -c Release
# Run the full test+corpus suite
dotnet test -c Release
# Pack locally to validate package metadata
dotnet pack -c Release -o ./bin/nuget
# Cut a release (manual, then push the tag)
git tag v0.1.0-alpha && git push origin v0.1.0-alpha