rtango 0.4.0

Package manager for AI agent skills, agents, and system instruction files
Documentation
# AGENTS.md

Context for AI agents working on the `rtango` codebase.

## What this repo is

`rtango` is a Rust CLI that acts as a package manager for AI-agent skills, agents, and system instruction files. A single source file is declared in `.rtango/spec.yaml` and rendered/synced into every supported agent's native layout (paths, frontmatter, permission vocabulary).

See `README.md` for the user-facing overview.

## Layout

```
src/
  main.rs              # thin entry, parses Cli and calls cmd::run
  lib.rs               # re-exports cmd
  cmd/                 # subcommand handlers (init, sync, status, own, add)
    mod.rs             # Cli + Command enum (clap derive) and dispatch
  spec/                # spec.yaml + lock.yaml data model and IO
  agent/               # per-agent support
    impls/             # claude_code.rs, copilot.rs, codex.rs, opencode.rs, pi.rs
    parse.rs / write.rs / frontmatter.rs / permission.rs / detect.rs
  engine/              # orchestration pipeline: expand → fetch → plan → execute
tests/                 # integration tests (run end-to-end against tempdirs)
demo/                  # worked example — real spec.yaml, lock.yaml, sample skills
```

## Pipeline mental model

`rtango sync` runs a fixed pipeline:

1. **expand** — spec rules → concrete `ExpandedItem`s (one item per source file × target agent).
2. **fetch** — resolve remote sources (GitHub refs) into the cache.
3. **parse** — the `schema_agent`'s parser reads frontmatter and permissions into a canonical representation.
4. **plan** — diff against `.rtango/lock.yaml`; classify each target as create / update / unchanged / conflict.
5. **execute** — write files, update the lock.

`status` stops after `plan`. `sync --check` exits non-zero if the plan is non-empty (CI gate).

## Core types

- `Spec` (`src/spec/spec.rs`) — `version`, `agents`, `defaults`, `rules`.
- `Rule``id`, `source`, `schema_agent`, `kind`, optional `include`/`exclude`, optional frontmatter overrides, optional per-rule `on_target_modified`.
- `Source` — local path or `github: owner/repo[@ref][:path]`.
- `Kind``skill`, `skill-set`, `agent`, `agent-set`, `system`.
- `Lock` — tracks rendered outputs, content hashes, ownership decisions.
- **Canonical permission set**: Read, Write, Edit, Shell, Grep, Glob, WebFetch, WebSearch, NotebookEdit, TodoWrite, Other. Each agent impl maps this set to its native tokens. Tokens an agent doesn't understand round-trip via `Other(_)`.

## Adding a new agent

1. Create `src/agent/impls/<agent>.rs` implementing the agent parser/writer/frontmatter/permission traits.
2. Register it in `src/agent/mod.rs`'s dispatcher.
3. Teach `init` auto-detection in `src/cmd/init.rs` if the agent has a well-known folder layout.
4. Add an integration test in `tests/`.

## Dev commands

```sh
cargo build                 # debug build
cargo build --release       # release binary in target/release/rtango
cargo test                  # unit + integration tests
cargo run -- <args>         # e.g. cargo run -- status
cargo clippy --all-targets  # lint
cargo fmt                   # format
```

For manual end-to-end testing, `cd demo` and run `../target/debug/rtango status`.

## Conventions

- Prefer editing existing modules over adding new top-level files.
- Integration tests use `tempfile::tempdir()` and a real project root — do not mock the filesystem.
- Lockfile ordering is deterministic; if you touch serialization, re-run `cargo test` and confirm snapshots still round-trip.
- When adding a CLI flag, keep the clap doc comments (`///`) concise — they become the `--help` output.
- Error handling uses `anyhow` at CLI boundaries and `thiserror` for typed module errors; follow the surrounding file's style.
- Don't hand-edit `.rtango/lock.yaml` in fixtures — regenerate it with `rtango sync` and commit the result.

## Gotchas

- The `schema_agent`'s own target path is auto-skipped when it equals the source path — a rule that names copilot as `schema_agent` and targets copilot's folder is a no-op for copilot but still renders for the other agents.
- A rule touching the same target path as another rule triggers an **ambiguity**; resolve with `rtango own <path> <rule-id>` which writes the decision into the lock.
- `on_target_modified: fail` (default) refuses to overwrite a file the user edited since the last sync. Use `--force` only when you genuinely want to discard local edits.
- System-kind rules (`CLAUDE.md`, `AGENTS.md`, …) live at the repo root and do not have frontmatter; the parser treats them as opaque content.