SuperAPI AI Directory

sift-init

Office & productivity

View repository

Updated 10-16 05:06

About this skill

Initialize Sift

Follow this contract in order. Resolve the project root first. Materialization is the only write, and it is idempotent.

Identity pin

The installable name must match the directory that holds this skill. The line below is machine-read by tests/static/skill-prose-pins.test.sh; its target ends in /, so the test looks for the construct in that directory's SKILL.md front matter.

@PIN: src/skills/sift-init/ name: sift-init

1. Resolve the root and inspect the tree

Input. Start from the canonicalized $PWD. SIFT_ROOT=/path overrides the walk. Resolve the gate script's absolute path once and reuse it.

Command. Every sift skill runs this before doing anything else:

scripts/sift-gate.sh

The gate reads only and never asks the user a question. Without SIFT_ROOT, it makes one upward walk to /, records the nearest match in each tier, then applies tier precedence:

Precedence Match Result
A -d $dir/.ai/sift adopt the existing tree
B -e $dir/.git use the repository root
C -f $dir/AGENTS.md or -f $dir/CLAUDE.md use the agent-instructed project root

A beats B, and B beats C, regardless of distance. Tier A prevents a nearer nested repository from splitting the ticket ID space after initialization. The .git check uses -e, because worktrees and submodules may store .git as a file. $HOME and / are inspected but excluded as roots, so a user-level agents file cannot claim them.

Output. The gate prints these key=value lines as applicable:

state=READY|INCOMPLETE|UNINITIALIZED|UNRESOLVED
root=<absolute path>
tier=A|B|C|override
marker=<matched entry>
corroboration=<other markers at the root, comma-separated, or none>
confidence=high|low
missing=<required entries, comma-separated>
prefix=<configured prefix>

root, tier, marker, and corroboration appear for a resolved root. confidence appears only for UNINITIALIZED, missing only for INCOMPLETE, and prefix only for READY. UNRESOLVED prints state=UNRESOLVED and writes the reason to stderr.

Result and required action. The exit code decides the next step:

Exit state= Required action
0 READY Proceed with the requested sift task.
3 UNINITIALIZED Tier B found a high-confidence root; initialize without asking about the root.
4 UNINITIALIZED Tier C found a low-confidence root; report the path and ask before writing.
5 UNRESOLVED Report the $PWD that was searched and ask for an explicit root.
6 INCOMPLETE Repair without asking, using the materialization command in step 3.
2 n/a Report the usage or environment error and stop.

tests/static/gate-handoff-contract.test.sh compares the exit 4 and 6 actions here with the gate script and both consuming skills.

2. Choose and validate the inputs

Input. Use ROOT from the gate. Choose an immutable prefix and, optionally, the first milestone. The prefix appears in every ticket ID, filename, and inline PREFIX-XXXX reference, so confirm it before any write. The default milestone is backlog.

Command. Derive a prefix suggestion, show it to the user, and allow an override:

scripts/sift-init.sh --suggest-prefix --root "$ROOT"

The suggestion strips non-alphanumerics from the root basename, uppercases it, and takes the first four characters. Exit 0 prints the suggestion. Exit 1 prints nothing, so ask the user for a prefix.

Validation. A supplied prefix must contain 2 to 8 uppercase ASCII letters or digits and start with a letter. A milestone must be lowercase kebab-case: lowercase letters and digits in hyphen-separated groups, such as backlog or v1-2. Empty values, path characters, spaces, uppercase milestone letters, and leading, trailing, or doubled milestone hyphens are invalid. Any invalid or missing input exits 2 before the script creates a directory.

3. Materialize or repair the tree

Input. Use the resolved ROOT, confirmed prefix, and optional milestone. An INCOMPLETE tree uses this same command. Keep its configured prefix when one exists; if the prefix is missing, choose and confirm one through step 2.

Command. Run:

scripts/sift-init.sh --root "$ROOT" --prefix ACME [--milestone <name>]

Created entries. The command creates only absent paths:

.ai/sift/
├── .gitignore             <- `*` and `!.gitignore`; fresh trees only
├── README.md              <- copied byte for byte from the skill assets
├── MILESTONES.md          <- generated with the first milestone
├── config/config.yaml     <- generated with the prefix
├── schemas/*.{xsd,xml}    <- schemas and optional XML example
├── scripts/sift.sh        <- local tracker operations
├── open/<milestone>/      <- empty; the first ticket creates its category
└── archive/               <- empty

README.md, scripts/sift.sh and the XSD/XML assets are copied byte for byte. A repeat run repairs missing entries and keeps every existing entry. It does not restore a missing .gitignore; that absence is the repository's opt-in to tracking the sift tree.

Publication guarantee. A bare mkdir claims .ai/sift, so one concurrent writer wins and the others enter the repair path. Each file is staged beside its destination, then published create-if-absent with ln; a writer that loses the link race keeps the file already published. Readers never see a partially written file. On a filesystem without hard-link support, the script falls back to a same-directory atomic mv.

Output and failures. Exit 0 prints the tree path, one created or kept line for each managed entry, prefix: <value> first milestone: <value>, and gate: READY. It may also print the comparison findings from step 4. Exit 2 reports a usage, filesystem, asset, publication, or final gate failure. Stop on exit 2 and report the diagnostic; never compensate by overwriting an existing path.

4. Review installed convention drift

Input and comparison. Compare README, script and XSD/XML assets with their installed copies. This check reads only.

Output. A differing installed copy prints a stale line. An installed schema that the skill no longer ships prints an orphan line. Matching files stay on the ordinary kept lines. The report offers these copy commands for stale files, with absolute paths already substituted:

cp <skill>/assets/README.md <root>/.ai/sift/README.md
cp <skill>/assets/schemas/*.xsd <skill>/assets/schemas/*.xml <root>/.ai/sift/schemas/
cp <skill>/assets/scripts/sift.sh <root>/.ai/sift/scripts/sift.sh

For each orphan, it prints an rm command instead. Copying cannot remove a withdrawn schema, and the installed file may be repository-owned.

Required action. Name the findings and offer the printed commands. Ask for explicit approval before running any copy or removal command. An installed spec may contain repository annotations, so refresh is never part of init or repair.

5. Report and stop

Report these fields after a successful run:

  • resolved root
  • permanent prefix
  • first milestone, noting that it is a placeholder
  • gate state READY
  • convention drift findings and offered remedies, if any
  • tracking policy and its opt-out

The default tracking policy is untracked. A fresh .ai/sift/.gitignore contains * and !.gitignore, so the tree ignores itself. Deleting that file opts the whole backlog into tracking. Ignore-aware search such as rg then skips an untracked sift tree; use find plus command grep when working inside it.

Never edit the repository root .gitignore. Init owns .ai/sift only. It does not create a first ticket, file any backlog work, or perform any requested sift task after the gate becomes ready.

6. Maintain the shipped assets

Sources are README.md, schemas/ and src/operations/sift.sh; shipped copies live in src/skills/sift-init/assets/. After changing a source, run:

src/skills/sift-init/scripts/sync-assets.sh

It copies the normative files, mirrors schema additions and removals, then exits non-zero if drift remains. Do not hand-copy the assets or add a separate diff step.