Skip to content

Latest commit

 

History

History
166 lines (124 loc) · 8.22 KB

File metadata and controls

166 lines (124 loc) · 8.22 KB

AGENTS.md

The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" in this document are to be interpreted as described in RFC 2119.

Project

clitest (CLI Test) — a Go CLI tool that runs declarative .clitest test files against shell commands. Single binary, zero dependencies.

  • Module: github.com/sleipi/cli-t
  • Binary output: ./clitest (repo root)
  • Spec: SPEC.md — the authoritative syntax reference; keep it in sync with code changes.

Tech Stack

  • Go

Workflow

  • You MUST work on a feature branch — never commit directly to main.
  • You MUST follow the Conventional Commits 1.0.0 specification for all commit messages.
  • You MUST write code using a TDD approach — write/update tests before implementation.
  • You MUST write E2E tests (in test/e2e/) for any new or changed behaviour.
  • You MUST NOT use @-prefixed directive names (e.g. @defer, @poll, @timeout) in commit messages or PR titles — GitHub interprets them as user mentions. Use backticks (`@defer`) or omit the @ prefix (e.g. "support defer directive").

Roadmap Management

  • ROADMAP.md is the source of truth for planned and completed features.
  • Each planned item SHOULD have a corresponding GitHub Issue — link it inline: [#N](url).
  • You MUST update ROADMAP.md when completing a planned feature — move the item from "Planned" to "Completed" and mark it [x]. Newest completed items MUST be placed at the top of the "Completed" list.
  • When creating new issues from roadmap items, use these labels:
    • enhancement — new features and functionality
    • eco — ecosystem (IDE plugins, docs, packaging, distribution)
    • tbd — needs further specification/discussion
  • Items without a GitHub Issue are parked at the bottom of the "Planned" list.
  • Duplicate items MUST be consolidated.

Branch Naming

Branch names MUST follow the format <type>/<short-description>.

Types: feat/, fix/, docs/, refactor/, test/, chore/

Rules:

  • You MUST use lowercase and hyphens as word separators (e.g. feat/add-capture-support).
  • You SHOULD keep names short but descriptive.
  • You MAY include an issue number (e.g. feat/42-capture-support).
  • You MUST NOT use special characters beyond hyphens and slashes.

Commands

make build        # go build -o clitest ./cmd/clitest/
make test         # go test ./...
make lint         # golangci-lint (static analysis, allow failure)
make e2e          # build + run ./clitest test/e2e/
make examples     # build + run ./clitest examples/
make all          # test + lint + e2e + examples (use this to verify changes)

Always run make all after changes — unit tests alone won't catch parser/CLI regressions.

Package Layout

cmd/clitest/main.go            CLI entrypoint
cmd/clitest/root.go            Cobra command setup, flags, orchestration (worker pools)
cmd/clitest/run.go             Entry orchestration with display coupling, loadAndParse
cmd/clitest/flags.go           varMap pflag type for --var
internal/display/              Rendering: ProgressDisplay, VerboseDisplay, ANSI colors, header/summary/failure output
internal/resolve/              File discovery: glob expansion, recursive dir walk, path resolution
internal/filter/               Group tag filtering (include/exclude)
internal/vars/                 Variable substitution (--var, captures, env expansion)
internal/executor/             Entry execution, background processes, defer handling
internal/parser/               .clitest format parser (entry builder, assert/capture parsing)
internal/runner/               Command execution via sh -c, captures stdout/stderr/exit/duration
internal/assert/               Predicate evaluation engine (queries + predicates + negation)
internal/types/                Shared types: Entry, Assert, Capture, File, Directives
examples/*.clitest             User-facing usage examples (also validated via `make examples`)
test/e2e/syntax/               E2E tests for .clitest syntax (asserts, captures, directives)
test/e2e/output/               E2E tests for header/footer/summary output and progress bar
test/e2e/options/              E2E tests for CLI flags (--var, --parallel, -v, --group)
test/e2e/resolve/              E2E tests for file discovery (recursive, glob, skip warnings)
test/e2e/background/           E2E tests for EXIT NEVER, @defer, @poll
test/_fixtures/                Shared test fixtures (e.g. intentionally failing .clitest files)

Conventions

  • TDD: write/update *_test.go before or alongside implementation.
  • test/e2e/ contains all E2E tests of the clitest tool itself — keep them green via make e2e.
  • examples/ contains user-facing usage demonstrations — validated via make examples.
  • Parser is hand-rolled (no parser generator). Entries separated by blank lines; sections by [Name] headers.
  • Values in asserts: "quoted" strings, /regex/ literals, or bare tokens. See unquoteValue in parser.
  • Runner always uses sh -c; commands can span multiple lines (trailing \ continuation).
  • Variable substitution ({{name}}) happens in cmd/clitest/run.go via internal/vars before parsing — it's a simple string replace, not part of the parser.
  • File discovery is recursive by default (--no-recursive to disable). Non-.clitest files are skipped with a warning to stderr.
  • Glob patterns in arguments (quoted, e.g. "examples/*.clitest") are expanded by clitest itself, not the shell. The original pattern is preserved in the header output.
  • EXIT NEVER marks background processes — runner starts them without waiting for exit, polls asserts until pass or @timeout.
  • @defer entries are cleanup (not tests): collected during parsing, executed LIFO at file end, errors logged but not failed.
  • @poll MS sets the polling interval for EXIT NEVER asserts (default 100ms).
  • pid is a capture query only available on EXIT NEVER entries.

Coding Guidelines

Behavioral guidelines to reduce common LLM coding mistakes. Merge with project-specific instructions as needed.

Tradeoff: These guidelines bias toward caution over speed. For trivial tasks, use judgment.

1. Think Before Coding

Don't assume. Don't hide confusion. Surface tradeoffs.

Before implementing:

  • State your assumptions explicitly. If uncertain, ask.
  • If multiple interpretations exist, present them - don't pick silently.
  • If a simpler approach exists, say so. Push back when warranted.
  • If something is unclear, stop. Name what's confusing. Ask.

2. Simplicity First

Minimum code that solves the problem. Nothing speculative.

  • No features beyond what was asked.
  • No abstractions for single-use code.
  • No "flexibility" or "configurability" that wasn't requested.
  • No error handling for impossible scenarios.
  • If you write 200 lines and it could be 50, rewrite it.

Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.

3. Surgical Changes

Touch only what you must. Clean up only your own mess.

When editing existing code:

  • Don't "improve" adjacent code, comments, or formatting.
  • Don't refactor things that aren't broken.
  • Match existing style, even if you'd do it differently.
  • If you notice unrelated dead code, mention it - don't delete it.

When your changes create orphans:

  • Remove imports/variables/functions that YOUR changes made unused.
  • Don't remove pre-existing dead code unless asked.

The test: Every changed line should trace directly to the user's request.

4. Goal-Driven Execution

Define success criteria. Loop until verified.

Transform tasks into verifiable goals:

  • "Add validation" → "Write tests for invalid inputs, then make them pass"
  • "Fix the bug" → "Write a test that reproduces it, then make it pass"
  • "Refactor X" → "Ensure tests pass before and after"

For multi-step tasks, state a brief plan:

1. [Step] → verify: [check]
2. [Step] → verify: [check]
3. [Step] → verify: [check]

Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.


These guidelines are working if: fewer unnecessary changes in diffs, fewer rewrites due to overcomplication, and clarifying questions come before implementation rather than after mistakes.