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
14 changes: 7 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ jobs:
# corpus from a missing one. Fail on absence explicitly, before checking.
run: |
set -euo pipefail
test -d intent || { echo "::error::corpus directory 'intent/' does not exist"; exit 1; }
test -d context/intent || { echo "::error::corpus directory 'context/intent/' does not exist"; exit 1; }

- name: strict check reports no diagnostics
run: |
set -euo pipefail
./target/release/intent check intent --profile strict --json > report.json || {
./target/release/intent check context/intent --profile strict --json > report.json || {
cat report.json >&2; exit 1;
}
jq -e '
Expand All @@ -81,7 +81,7 @@ jobs:
# a wrong path, and non-empty only when artifacts were genuinely read.
run: |
set -euo pipefail
./target/release/intent graph intent --json > graph.json
./target/release/intent graph context/intent --json > graph.json
nodes="$(jq '.nodes | length' graph.json)"
echo "graph nodes: $nodes"
jq -e '(.nodes | length) > 0' graph.json > /dev/null \
Expand All @@ -97,8 +97,8 @@ jobs:
- name: fixtures and the enforcement schema are present
run: |
set -euo pipefail
fixtures="intent/15-evaluation/semantic-review"
schema="intent/16-enforcement/review-result.schema.json"
fixtures="context/intent/15-evaluation/semantic-review"
schema="context/intent/16-enforcement/review-result.schema.json"
test -d "$fixtures" || { echo "::error::missing fixtures root: $fixtures"; exit 1; }
test -f "$fixtures/fixture-format.md" || { echo "::error::missing fixture-format.md"; exit 1; }
test -f "$schema" || { echo "::error::missing review-result schema: $schema"; exit 1; }
Expand All @@ -107,8 +107,8 @@ jobs:
# Fully offline: every schema is a local file, so none is ever fetched.
run: |
set -euo pipefail
fixtures="intent/15-evaluation/semantic-review"
schema="intent/16-enforcement/review-result.schema.json"
fixtures="context/intent/15-evaluation/semantic-review"
schema="context/intent/16-enforcement/review-result.schema.json"
found=0
for fixture in "$fixtures"/*/; do
[ -d "$fixture" ] || continue
Expand Down
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ people who were there. The problem is not that the knowledge is missing; it is
that nothing says which of those places is authoritative, so none of them can be
trusted, and none can be checked.

`intent/` is that contract, specified in itself. The corpus in this repository
uses its own conventions to define its own conventions — `intent/vision.md` is a
vision document written to the rules that `intent/01-vision/` specifies.
`context/intent/` is that contract, specified in itself. The corpus in this repository
uses its own conventions to define its own conventions — `context/intent/vision.md` is a
vision document written to the rules that `context/intent/01-vision/` specifies.

## What it is for

Expand All @@ -37,10 +37,10 @@ the middle of the specification.

Read in this order:

1. **`intent/vision.md`** — what this is and what it deliberately is not.
2. **`intent/requirements.md`** — the constraints the contract holds itself to.
3. **`intent/spec.md`** — how the artifacts fit together.
4. **`intent/ontology.md`** — the vocabulary. Worth reading early; the terms are
1. **`context/intent/vision.md`** — what this is and what it deliberately is not.
2. **`context/intent/requirements.md`** — the constraints the contract holds itself to.
3. **`context/intent/spec.md`** — how the artifacts fit together.
4. **`context/intent/ontology.md`** — the vocabulary. Worth reading early; the terms are
used precisely and the precision is the point.

Then follow whichever numbered section matches the artifact you care about.
Expand Down
4 changes: 2 additions & 2 deletions context/cli/requirements.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@

This document defines testable constraints for the `intent` CLI: Intent hygiene,
graph extraction, and enforcement diagnostics. It builds on the enforcement contract in
[intent/16-enforcement](../../intent/16-enforcement/).
[intent/16-enforcement](../intent/16-enforcement/).

The `AXE.INTENT-*` requirement namespace is a stable document identifier carried
from the originating CLI contract; it does not name an executable command.

## Assumptions

- **A01 Intent owns semantics:** The root contract in [intent](../../intent/)
- **A01 Intent owns semantics:** The root contract in [intent](../intent/)
owns artifact semantics, file contracts, review smells, and enforcement rules.
- **A02 CLI owns operator ergonomics:** `intent` gives humans and agents one
discoverable command surface for Intent checks without making the CLI the
Expand Down
10 changes: 5 additions & 5 deletions context/cli/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ Defines:
Does not define:

- Intent artifact semantics, file contracts, review smells, or enforcement rules;
see [intent](../../intent/) and
[intent/16-enforcement](../../intent/16-enforcement/);
see [intent](../intent/) and
[intent/16-enforcement](../intent/16-enforcement/);
- semantic LLM review rubric content beyond routing diagnostics;
- future typed-source Intent authoring;
- Plan storage or workflow semantics.
Expand Down Expand Up @@ -250,11 +250,11 @@ emits an ambiguous-structure diagnostic rather than inventing a node or edge.
bounded review packet from:

- the baked Intent semantic-review prompt owned at
[intent/16-enforcement/review-prompt.md](../../intent/16-enforcement/review-prompt.md);
[intent/16-enforcement/review-prompt.md](../intent/16-enforcement/review-prompt.md);
- the target Intent files;
- `intent check --json` diagnostics;
- the semantic review output schema at
[intent/16-enforcement/review-result.schema.json](../../intent/16-enforcement/review-result.schema.json).
[intent/16-enforcement/review-result.schema.json](../intent/16-enforcement/review-result.schema.json).

The command invokes `$CODING_AGENT` through the Coding Agent Invocation Contract
(specified in `context/coding-agents/22-invocation-contract/spec.md` in the
Expand Down Expand Up @@ -333,7 +333,7 @@ not imply a nonzero exit code unless a future explicit fail policy is added.
## Fixture Review Grading

`intent review-fixtures` is the runner for the semantic-review fixtures owned by
[intent/15-evaluation](../../intent/15-evaluation/spec.md). It exists so the
[intent/15-evaluation](../intent/15-evaluation/spec.md). It exists so the
minimum-assertion contract is executable rather than descriptive.

For each selected fixture it:
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

### Must Apply Intent, Not Redefine It

- **INTENT.GRILL-R01 Intent contract source:** `intent/` is the source of truth
- **INTENT.GRILL-R01 Intent contract source:** `context/intent/` is the source of truth
for artifact structure, lifecycle, and review rules.
- **INTENT.GRILL-R02 Procedural skill:** `grill-intent` owns the interview procedure:
questioning, pressure-testing, validation, and inline Intent updates.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Draft.
## Relationship

```text
intent/ normative intent-layer contract
context/intent/ normative intent-layer contract
grill-intent procedure that interrogates and updates the contract
```

Expand All @@ -34,6 +34,6 @@ arrives at those facts with a human or through code/research investigation.
## Skill Reduction

When the operational skill is updated, it should keep procedural rules and link
to `intent/` for artifact details. The skill should not carry independent
to `context/intent/` for artifact details. The skill should not carry independent
templates for decisions, ontology, requirements, experiments, deltas, or roadmap
when the root Intent contract already defines them.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ owned by [16-enforcement](../../16-enforcement/spec.md).
Each fixture should live in a stable, descriptive directory:

```text
intent/15-evaluation/semantic-review/<fixture-slug>/
context/intent/15-evaluation/semantic-review/<fixture-slug>/
fixture.json
input/
context/<scenario>/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ The scenario should include at least:

## Eval Procedure

1. Read `intent/` and `nixpkgs/ai/skills/grill-intent.md`.
1. Read `context/intent/` and `nixpkgs/ai/skills/grill-intent.md`.
2. Create the scenario in a temporary directory outside tracked repo files.
3. Apply the `grill-intent` procedure as if shaping the scenario with a user.
4. Produce the miniature Intent tree.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Classify semantic Intent issues that deterministic lint cannot prove safely:
- Empty companion directories or README-style Intent entry points appear where the
root Intent contract does not allow them.

Use the review-smell catalog in `intent/13-review-smells/spec.md` as the
Use the review-smell catalog in `context/intent/13-review-smells/spec.md` as the
primary rubric when it is supplied.

## Finding Rules
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ the proposed strict shape, but the wider `context/**/.decisions` corpus is not
ready for repo-wide blocking without migration or scoped enforcement.

Initial strict decision-shape enforcement applies only to
`intent/.decisions/`. Other `context/**/.decisions/` records may be scanned
`context/intent/.decisions/`. Other `context/**/.decisions/` records may be scanned
for migration diagnostics later, but they are not part of the first strict
decision-shape scope.

Expand Down Expand Up @@ -138,7 +138,7 @@ mode; prompt and schema changes are Intent changes and should be evaluated throu
fixtures before becoming the baked version.

Real-provider execution policy is owned by the
[Intent command spec](../../context/cli/spec.md). Enforcement
[Intent command spec](../../cli/spec.md). Enforcement
owns the baked prompt, result schema, semantic finding shape, and fixture-backed
quality evidence. The command spec owns when providers may run, which CAIC
contract pieces are required, and how stdout/report routing behaves.
Expand All @@ -152,7 +152,7 @@ Structured enforcement output should preserve enough routing context for agents:
"kind": "deterministic | semantic",
"severity": "error | warning | info",
"gate": "blocking | advisory | review",
"artifact": "intent/requirements.md",
"artifact": "context/intent/requirements.md",
"owner": "02-requirements",
"rule": "INTENT.ENF.<rule-id>",
"evidence": "Requirement IDs skip INTENT-R12.",
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion intent/spec.md → context/intent/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ validate assumptions, compare against code and references, and update the
correct Intent artifact as understanding crystallizes.

The procedure must not duplicate detailed artifact rules that live in
`intent/`; it should point to the root Intent contract and stay focused on how
`context/intent/`; it should point to the root Intent contract and stay focused on how
to conduct the interview.

Ontology handling is part of `grill-intent`, not a separate skill by default.
Expand Down
2 changes: 1 addition & 1 deletion intent/vision.md → context/intent/vision.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ working state.
3. Proposed decisions, experiments, references, and deltas have clear lifecycles
and do not pollute the durable contract.
4. Operational skills such as `intent.md` and `grill-intent` can become thin
procedures over the normative `intent/` contract.
procedures over the normative `context/intent/` contract.
2 changes: 1 addition & 1 deletion crates/intent/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ name = "intent"
path = "src/lib.rs"

[dependencies]
clap = { version = "4.5", features = ["derive", "env"] }
clap = { version = "4.5", features = ["derive", "env", "string"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
# Runtime, not just tests: `review` stages the diagnostics packet and the CAIC
Expand Down
73 changes: 61 additions & 12 deletions crates/intent/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use clap::{Parser, Subcommand, ValueEnum};
use clap::{CommandFactory, FromArgMatches, Parser, Subcommand, ValueEnum};
use serde::Serialize;
use serde_json::Value;
use std::collections::{BTreeSet, HashSet};
use std::ffi::OsStr;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process::{Command, ExitCode};

const CORPUS: &str = "context/intent";

// Positions INSIDE a corpus, so they hold for any repository that adopts the
// layout. Resolving the review assets relative to the corpus root rather than the
// repository root is what keeps tool and corpus co-located: `review` reads both
Expand Down Expand Up @@ -214,6 +216,30 @@ impl Defaults {
fn fixtures_or_default(&self, arg: Option<PathBuf>) -> PathBuf {
arg.unwrap_or_else(|| self.corpus_root.join(SEMANTIC_REVIEW_SUBDIR))
}

pub fn command(&self) -> clap::Command {
let root = self.corpus_root.clone().into_os_string();
let fixtures = self
.corpus_root
.join(SEMANTIC_REVIEW_SUBDIR)
.into_os_string();
IntentCli::command()
.mut_subcommand("check", |cmd| default_root(cmd, root.clone()))
.mut_subcommand("graph", |cmd| default_root(cmd, root.clone()))
.mut_subcommand("review", |cmd| default_root(cmd, root))
.mut_subcommand("review-fixtures", |cmd| default_root(cmd, fixtures))
}

pub fn parse(&self) -> IntentCli {
match IntentCli::from_arg_matches_mut(&mut self.command().get_matches()) {
Ok(cli) => cli,
Err(error) => error.exit(),
}
}
}

fn default_root(cmd: clap::Command, value: OsString) -> clap::Command {
cmd.mut_arg("root", |arg| arg.default_value(value))
}

impl Default for Defaults {
Expand Down Expand Up @@ -1198,12 +1224,12 @@ pub fn graph_root(root: &Path) -> Result<GraphReport, Box<dyn std::error::Error>
})
}

// Corpus-relative only. A removed fallback guessed a repository-specific
// `.decisions` path when handed a repository root. That was silently wrong for
// other layouts and let a misaimed invocation look clean. Pointing this at a
// corpus is the caller's job.
fn root_intent_decision_dir(root: &Path) -> PathBuf {
root.join(".decisions")
let direct = root.join(".decisions");
if direct.is_dir() {
return direct;
}
root.join(CORPUS).join(".decisions")
}

fn check_markdown_links(
Expand Down Expand Up @@ -1623,13 +1649,11 @@ fn markdown_files_direct(dir: &Path) -> Result<Vec<PathBuf>, Box<dyn std::error:
/// artifacts may not escape.
///
/// This is still repository-scoped rather than corpus-scoped: a reviewer reasoning
/// about a corpus needs the repository around it. A removed repository-specific
/// sentinel was only reached when `.git` was absent. Falling back to the corpus
/// root keeps that no-`.git` case working without teaching the tool a repository
/// layout.
/// about a corpus needs the repository around it. In exported trees and build
/// sandboxes without `.git`, the canonical corpus position identifies that boundary.
fn review_workspace(root: &Path) -> PathBuf {
for ancestor in root.ancestors() {
if ancestor.join(".git").exists() {
if ancestor.join(".git").exists() || ancestor.join(CORPUS).is_dir() {
return ancestor.to_path_buf();
}
}
Expand Down Expand Up @@ -2263,6 +2287,21 @@ mod tests {
);
}

#[test]
fn a_callers_default_reaches_the_help_it_renders() {
let defaults = Defaults::corpus_root("context/intent");
let check = defaults
.command()
.find_subcommand_mut("check")
.expect("check subcommand")
.render_help()
.to_string();
assert!(
check.contains("[default: context/intent]"),
"help:\n{check}"
);
}

// Covers the fallback used when there is no `.git`, such as a Nix build
// sandbox or vendored source tree. Interactive runs normally take the
// enclosing-repository branch instead.
Expand All @@ -2275,6 +2314,16 @@ mod tests {
assert_eq!(review_workspace(&corpus), corpus);
}

#[test]
fn review_workspace_finds_the_repository_by_corpus_layout_when_there_is_no_git() {
let tempdir = tempfile::tempdir().unwrap();
let repo = fs::canonicalize(tempdir.path()).unwrap();
let corpus = repo.join("context/intent");
fs::create_dir_all(&corpus).unwrap();

assert_eq!(review_workspace(&corpus), repo);
}

#[test]
fn review_workspace_prefers_the_enclosing_repository() {
let tempdir = tempfile::tempdir().unwrap();
Expand Down
4 changes: 2 additions & 2 deletions crates/intent/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use clap::Parser;
use std::process::ExitCode;

// The binary is a thin shell over the library entry point so standalone and
// embedded callers execute the same checker behavior.
fn main() -> ExitCode {
intent::run(intent::IntentCli::parse())
let defaults = intent::Defaults::default();
intent::run_with(defaults.parse(), &defaults)
}
Loading
Loading