Skip to content
Open
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
28 changes: 28 additions & 0 deletions .specify/integrations/copilot.manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This integration manifest records SHA-256 hashes for 22 files (.github/agents/, .github/prompts/, .vscode/settings.json) that do not exist in this repository — they were copied verbatim from iklo. Since speckit.manifest.json correctly references files present under .specify/, the copilot manifest is the only inconsistent one: any tooling that verifies/installs by this manifest will flag every entry as missing. Consider regenerating the manifest for this repo or omitting it until the referenced files land.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .specify/integrations/copilot.manifest.json, line 6:

<comment>This integration manifest records SHA-256 hashes for 22 files (.github/agents/*, .github/prompts/*, .vscode/settings.json) that do not exist in this repository — they were copied verbatim from iklo. Since speckit.manifest.json correctly references files present under .specify/, the copilot manifest is the only inconsistent one: any tooling that verifies/installs by this manifest will flag every entry as missing. Consider regenerating the manifest for this repo or omitting it until the referenced files land.</comment>

<file context>
@@ -0,0 +1,28 @@
+  "version": "0.12.18",
+  "installed_at": "2026-07-17T15:07:12.587971+00:00",
+  "files": {
+    ".github/agents/speckit.analyze.agent.md": "07e1e9f997bce9e06d3823ecf1ed315bb62381b81e7d6a7aef19c5087c320e70",
+    ".github/agents/speckit.clarify.agent.md": "595ae8988179a91780ce10e258afcccaa313b0924a79e720c66226e31af7ec00",
+    ".github/agents/speckit.constitution.agent.md": "e0d1d7c237d4657914dcccb6ea0c3a3a10d8d1d9a36b198282e22b3d0b9a55e5",
</file context>

"integration": "copilot",
"version": "0.12.18",
"installed_at": "2026-07-17T15:07:12.587971+00:00",
"files": {
".github/agents/speckit.analyze.agent.md": "07e1e9f997bce9e06d3823ecf1ed315bb62381b81e7d6a7aef19c5087c320e70",
".github/agents/speckit.clarify.agent.md": "595ae8988179a91780ce10e258afcccaa313b0924a79e720c66226e31af7ec00",
".github/agents/speckit.constitution.agent.md": "e0d1d7c237d4657914dcccb6ea0c3a3a10d8d1d9a36b198282e22b3d0b9a55e5",
".github/agents/speckit.implement.agent.md": "6a5713a4db8d48dd7c93e38b9957c6e54b6b7dc899ebab66f9ccb3bce58fdfeb",
".github/agents/speckit.converge.agent.md": "e585bc94a3f01cb45eb4f4f6003268a7bc7e1f1685d343c25ad5dc3c484b4816",
".github/agents/speckit.plan.agent.md": "ff1809d5d72b399ec364414a150c1a20e782677972d11f0bdf8c65c73f898a71",
".github/agents/speckit.checklist.agent.md": "2124a817bddbff7f469fd47b08e43dd9a39b769499d367f6888a74e1e821412d",
".github/agents/speckit.specify.agent.md": "e24c01f27d269dab73c4178ce5bb1c31198dbfc36b9198cc6e407ef1122f4745",
".github/agents/speckit.tasks.agent.md": "e3569f2fbdb99704b81e3647ce9e52fb812764d6b2590fc497a2c2130b43ba72",
".github/agents/speckit.taskstoissues.agent.md": "0a436a42ceca2db309df88985d1939ee7f176c4a7a2d7c7a8d2253006cfe6870",
".github/prompts/speckit.analyze.prompt.md": "bb93dbbafa96d07b7cd07fc7061d8adb0c6b26cb772a52d0dce263b1ca2b9b77",
".github/prompts/speckit.clarify.prompt.md": "ce79b3437ca918d46ac858eb4b8b44d3b0a02c563660c60d94c922a7b5d8d4f4",
".github/prompts/speckit.constitution.prompt.md": "38f937279de14387601422ddfda48365debdbaf47b2d513527b8f6d8a27d499d",
".github/prompts/speckit.implement.prompt.md": "5053a17fb9238338c63b898ee9c80b2cb4ad1a90c6071fe3748de76864ac6a80",
".github/prompts/speckit.converge.prompt.md": "8e37fe6d8b6ce130fcc011b995edd3e412d825c0f46abd1a7706451f2049d571",
".github/prompts/speckit.plan.prompt.md": "2098dae6bd9277335f31cb150b78bfb1de539c0491798e5cfe382c89ab0bcd0e",
".github/prompts/speckit.checklist.prompt.md": "c3aea7526c5cbfd8665acc9508ad5a9a3f71e91a63c36be7bed13a834c3a683c",
".github/prompts/speckit.specify.prompt.md": "7b2cc4dc6462da1c96df46bac4f60e53baba3097f4b24ac3f9b684194458aa98",
".github/prompts/speckit.tasks.prompt.md": "88fc57c289f99d5e9d35c255f3e2683f73ecb0a5155dcb4d886f82f52b11841f",
".github/prompts/speckit.taskstoissues.prompt.md": "2f9636d4f312a1470f000747cb62677fec0655d8b4e2357fa4fbf238965fa66d",
".vscode/settings.json": "3db3a1d8417d38a56b405f60b600dce666b4fc47be7fe332a0b051c4bd1fd4b7"
}
}
17 changes: 17 additions & 0 deletions .specify/integrations/speckit.manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"integration": "speckit",
"version": "0.12.18",
"installed_at": "2026-07-17T15:07:12.597929+00:00",
"files": {
".specify/scripts/bash/common.sh": "6ff86bf39f6b4684b0f80927dc7a1dadec26b4671988a3fe4d6c2523cbd3aa22",
".specify/scripts/bash/setup-plan.sh": "4469b22960f43c07c33dca00de6dedb252145e9a9ce8fbb0e63be82e02b082ab",
".specify/scripts/bash/setup-tasks.sh": "1d4bcebe93f3e4e778964978cfe9bfb67ee94e7dc688f2ff3be224f647f61f1f",
".specify/scripts/bash/check-prerequisites.sh": "ac3e96258a05d029d048076393a03aadff5c7c3a55a26d0a9f5c17886a1c659d",
".specify/scripts/bash/create-new-feature.sh": "dd531f9ba47c9ce9975b597947377be9542b7236681d6dc033513c4e3cfc50f2",
".specify/templates/constitution-template.md": "ce7549540fa45543cca797a150201d868e64495fdff39dc38246fb17bd4024b3",
".specify/templates/checklist-template.md": "0ad704b60af2df817aee1c0a2ecc0e0304b271d2de34047df1c891735967033e",
".specify/templates/tasks-template.md": "c731575d8099b3f871861186fbd1a592b51b2ba57fb99e1a0dab439ff6d5608f",
".specify/templates/spec-template.md": "3945437fc35cd30a5b2bf7beea680337c3516826d3efa5a6b92c4a7eca1ba28e",
".specify/templates/plan-template.md": "5ef0e4c97b36e9f91372dc6eb8e5a7e515af8958cf1a9286e43a1ebd9bd48540"
}
}
107 changes: 107 additions & 0 deletions .specify/memory/constitution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# guiltty Constitution

These are the principles that govern every spec, plan, and task in this
repo. They supersede convenience. Amendments require an ADR under
`specs/decisions/` (added alongside this file by issue #39's task
breakdown -- not yet a live link here since task merge order isn't
guaranteed).

## Core Principles

### I. Backend-Agnostic Core

`guiltty-core` stays scoped to the absolute-coordinate drawing surface
(`Canvas`, `Shape`, text, the `Backend` trait) and never contains
backend-specific code; backend concerns live only in backend crates
(`guiltty-kitty` today). Crates built on `guiltty-core`'s public API
(`guiltty-sprite`, and `guiltty-turtle` once it exists) follow the same
rule one level up: they never reach into another crate's private state,
only its public API. Adding a new backend crate, or changing the workspace
crate boundaries this describes, is an **ask-first** change.

### II. Recoverable Errors Never Panic

Public API returns `Result<T, guiltty_core::Error>` for recoverable
conditions (a missing/malformed image file, a failed terminal write, a
stale sprite footprint) rather than panicking. Panics are reserved for
programmer-error invariants only (e.g. an out-of-bounds internal index) --
never a condition a caller could legitimately hit and need to recover
from.

### III. Ask First On New Dependencies

Adding any new external dependency (especially anything requiring C/FFI)
is an **ask-first** change, same as a new backend crate or workspace
boundary change (Principle I). Removing one usually isn't.

### IV. Test-First For Behavioral Changes

Every behavioral change lands with tests that actually assert the new
behavior -- not coverage-padding. `guiltty-core`/`guiltty-sprite` unit
tests assert pixel-buffer/state correctness with no terminal required;
`guiltty-kitty` protocol tests assert byte-level escape-sequence encoding;
actual rendered output stays a manual/visual check for now (see
`docs/spec-kitty-e2e.md` for the planned automated tier). CI enforces a
90% line-coverage floor (`docs/spec-ci.md`) -- a PR that drops below it
fails, but clearing the floor is a side effect of real tests, never the
goal itself.

### V. Pre-1.0 Breaking Changes Are Cheap, Not Silent

Every crate in this workspace is at `0.0.0`. Breaking a public API
pre-1.0 is acceptable and sometimes the right call (see the
`guiltty-sprite` extraction's precedent) -- but it must be called out
explicitly in the PR description as a breaking change, never shipped as
if it were routine.

### VI. Docs That Contradict Code Are Bugs

A stale "not yet implemented" note, a broken doc link, a crate list
missing a crate that now exists -- these are bugs, not polish, and they
only get more misleading the longer they're left. Fix doc staleness
encountered while touching the affected area in the same PR, not a
follow-up (`docs/spec.md`'s crate list went stale exactly this way after
the `guiltty-sprite` extraction, and was fixed as part of the same repo-

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Principle VI asserts docs/spec.md's crate list "was fixed" after the guiltty-sprite extraction, but today that list still omits guiltty-sprite and still describes sprites as living in guiltty-core. Since this document governs the repo and explicitly calls doc/code contradictions bugs, this inaccurate claim should be corrected (or the crate list actually fixed in this PR) before it spreads the exact staleness the principle warns about.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .specify/memory/constitution.md, line 64:

<comment>Principle VI asserts `docs/spec.md`'s crate list "was fixed" after the `guiltty-sprite` extraction, but today that list still omits `guiltty-sprite` and still describes sprites as living in `guiltty-core`. Since this document governs the repo and explicitly calls doc/code contradictions bugs, this inaccurate claim should be corrected (or the crate list actually fixed in this PR) before it spreads the exact staleness the principle warns about.</comment>

<file context>
@@ -0,0 +1,107 @@
+only get more misleading the longer they're left. Fix doc staleness
+encountered while touching the affected area in the same PR, not a
+follow-up (`docs/spec.md`'s crate list went stale exactly this way after
+the `guiltty-sprite` extraction, and was fixed as part of the same repo-
+standard bootstrap this constitution belongs to -- see issue #39).
+
</file context>

standard bootstrap this constitution belongs to -- see issue #39).

## Development Constraints

- **Rust**, latest stable toolchain, 2021 edition, no nightly-only
features. Toolchain pinned via [`mise.toml`](../../mise.toml).
- **Structure:** a Cargo workspace, not a single crate -- see Principle I.
- **Color/coordinates:** RGBA8 throughout; pixel-addressable, origin
top-left.
- Full tech-stack rationale (why `kittage` over hand-rolled encoding, why
`notcurses`/GPU acceleration are out of scope for now, etc.) lives in
[`docs/spec.md`](../../docs/spec.md), not restated here.

## Workflow

Unlike iklo's spec-kit-driven `/speckit.*` gates, this repo's day-to-day
shipping process predates `.specify/` and stays as-is: the
`pull-request-process`/`map-issue-to-tasks`/`fix-mapped-issue` skills --
worktrees (never the shared checkout), a dedicated git/PR identity,
issue → `tasks/issue-N-*.md` task breakdown → one task per PR → bots/the
maintainer review and merge, never self-merged. `.specify/`'s templates
and scripts are bootstrapped (issue #39) for future spec-kit-format work
under `specs/NNN-slug/`, alongside this process, not replacing it.

**Bugs and feature work** are GitHub Issues on
[rsenna/guiltty](https://github.com/rsenna/guiltty/issues). Promote one
into a `specs/NNN-slug/spec.md` when it grows into real design work worth
the spec-kit gates; smaller decisions can stay as a `docs/design/*.md`
write-up (this repo's existing convention, e.g.
[`docs/design/viewport-regions-zoom-scroll.md`](../../docs/design/viewport-regions-zoom-scroll.md))
or an ADR under `specs/decisions/`.

## Governance

- These principles supersede all other practices in the repo.
- Amendments require an ADR (context, alternatives rejected,
consequences) under `specs/decisions/`.
- Every PR/review verifies compliance.
- Day-to-day agent operating guidance lives in `AGENTS.md` (added
alongside this file by issue #39's task breakdown -- not yet a live
link here since task merge order isn't guaranteed).

**Version**: 1.0.0 | **Ratified**: 2026-08-02 | **Last Amended**: 2026-08-02
195 changes: 195 additions & 0 deletions .specify/scripts/bash/check-prerequisites.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
#!/usr/bin/env bash

# Consolidated prerequisite checking script
#
# This script provides unified prerequisite checking for Spec-Driven Development workflow.
# It replaces the functionality previously spread across multiple scripts.
#
# Usage: ./check-prerequisites.sh [OPTIONS]
#
# OPTIONS:
# --json Output in JSON format
# --require-tasks Require tasks.md to exist (for implementation phase)
# --include-tasks Include tasks.md in AVAILABLE_DOCS list
# --paths-only Only output path variables (no validation)
# --help, -h Show help message
#
# OUTPUTS:
# JSON mode: {"FEATURE_DIR":"...", "AVAILABLE_DOCS":["..."]}
# Text mode: FEATURE_DIR:... \n AVAILABLE_DOCS: \n ✓/✗ file.md
# Paths only: REPO_ROOT: ... \n BRANCH: ... \n FEATURE_DIR: ... etc.

set -e

# Parse command line arguments
JSON_MODE=false
REQUIRE_TASKS=false
INCLUDE_TASKS=false
PATHS_ONLY=false

for arg in "$@"; do
case "$arg" in
--json)
JSON_MODE=true
;;
--require-tasks)
REQUIRE_TASKS=true
;;
--include-tasks)
INCLUDE_TASKS=true
;;
--paths-only)
PATHS_ONLY=true
;;
--help|-h)
cat << 'EOF'
Usage: check-prerequisites.sh [OPTIONS]

Consolidated prerequisite checking for Spec-Driven Development workflow.

OPTIONS:
--json Output in JSON format
--require-tasks Require tasks.md to exist (for implementation phase)
--include-tasks Include tasks.md in AVAILABLE_DOCS list
--paths-only Only output path variables (no prerequisite validation)
--help, -h Show this help message

EXAMPLES:
# Check task prerequisites (plan.md required)
./check-prerequisites.sh --json

# Check implementation prerequisites (plan.md + tasks.md required)
./check-prerequisites.sh --json --require-tasks --include-tasks

# Get feature paths only (no validation)
./check-prerequisites.sh --paths-only

EOF
exit 0
;;
*)
echo "ERROR: Unknown option '$arg'. Use --help for usage information." >&2
exit 1
;;
esac
done

# Source common functions
SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/common.sh"

# Get feature paths.
# In --paths-only mode this is pure resolution, so pass --no-persist to opt out
# of the feature.json write side effect (issue #3025).
if $PATHS_ONLY; then
_paths_output=$(get_feature_paths --no-persist) || { echo "ERROR: Failed to resolve feature paths" >&2; exit 1; }
else
_paths_output=$(get_feature_paths) || { echo "ERROR: Failed to resolve feature paths" >&2; exit 1; }
fi
eval "$_paths_output"
unset _paths_output

# If paths-only mode, output paths and exit (no validation)
if $PATHS_ONLY; then
if $JSON_MODE; then
# Minimal JSON paths payload (no validation performed)
if has_jq; then
jq -cn \
--arg repo_root "$REPO_ROOT" \
--arg branch "$CURRENT_BRANCH" \
--arg feature_dir "$FEATURE_DIR" \
--arg feature_spec "$FEATURE_SPEC" \
--arg impl_plan "$IMPL_PLAN" \
--arg tasks "$TASKS" \
'{REPO_ROOT:$repo_root,BRANCH:$branch,FEATURE_DIR:$feature_dir,FEATURE_SPEC:$feature_spec,IMPL_PLAN:$impl_plan,TASKS:$tasks}'
else
printf '{"REPO_ROOT":"%s","BRANCH":"%s","FEATURE_DIR":"%s","FEATURE_SPEC":"%s","IMPL_PLAN":"%s","TASKS":"%s"}\n' \
"$(json_escape "$REPO_ROOT")" "$(json_escape "$CURRENT_BRANCH")" "$(json_escape "$FEATURE_DIR")" "$(json_escape "$FEATURE_SPEC")" "$(json_escape "$IMPL_PLAN")" "$(json_escape "$TASKS")"
fi
else
echo "REPO_ROOT: $REPO_ROOT"
echo "BRANCH: $CURRENT_BRANCH"
echo "FEATURE_DIR: $FEATURE_DIR"
echo "FEATURE_SPEC: $FEATURE_SPEC"
echo "IMPL_PLAN: $IMPL_PLAN"
echo "TASKS: $TASKS"
fi
exit 0
fi

# Validate required directories and files
if [[ ! -d "$FEATURE_DIR" ]]; then
echo "ERROR: Feature directory not found: $FEATURE_DIR" >&2
echo "Run /speckit.specify first to create the feature structure." >&2
exit 1
fi

if [[ ! -f "$IMPL_PLAN" ]]; then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Task prerequisite checks report success when spec.md is missing, so callers can advance past this check and then fail in setup-tasks.sh. Validate $FEATURE_SPEC alongside $IMPL_PLAN and return the existing /speckit.specify guidance.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .specify/scripts/bash/check-prerequisites.sh, line 127:

<comment>Task prerequisite checks report success when `spec.md` is missing, so callers can advance past this check and then fail in `setup-tasks.sh`. Validate `$FEATURE_SPEC` alongside `$IMPL_PLAN` and return the existing `/speckit.specify` guidance.</comment>

<file context>
@@ -0,0 +1,195 @@
+    exit 1
+fi
+
+if [[ ! -f "$IMPL_PLAN" ]]; then
+    echo "ERROR: plan.md not found in $FEATURE_DIR" >&2
+    echo "Run /speckit.plan first to create the implementation plan." >&2
</file context>

echo "ERROR: plan.md not found in $FEATURE_DIR" >&2
echo "Run /speckit.plan first to create the implementation plan." >&2
exit 1
fi

# Check for tasks.md if required
if $REQUIRE_TASKS && [[ ! -f "$TASKS" ]]; then
echo "ERROR: tasks.md not found in $FEATURE_DIR" >&2
echo "Run /speckit.tasks first to create the task list." >&2
exit 1
fi

# Build list of available documents
docs=()

# Always check these optional docs
[[ -f "$RESEARCH" ]] && docs+=("research.md")
[[ -f "$DATA_MODEL" ]] && docs+=("data-model.md")

# Check contracts directory (only if it exists and has files)
if [[ -d "$CONTRACTS_DIR" ]] && [[ -n "$(ls -A "$CONTRACTS_DIR" 2>/dev/null)" ]]; then
docs+=("contracts/")
fi

[[ -f "$QUICKSTART" ]] && docs+=("quickstart.md")

# Include tasks.md if requested and it exists
if $INCLUDE_TASKS && [[ -f "$TASKS" ]]; then
docs+=("tasks.md")
fi

# Output results
if $JSON_MODE; then
# Build JSON array of documents
if has_jq; then
if [[ ${#docs[@]} -eq 0 ]]; then
json_docs="[]"
else
json_docs=$(printf '%s\n' "${docs[@]}" | jq -R . | jq -s .)
fi
jq -cn \
--arg feature_dir "$FEATURE_DIR" \
--argjson docs "$json_docs" \
'{FEATURE_DIR:$feature_dir,AVAILABLE_DOCS:$docs}'
else
if [[ ${#docs[@]} -eq 0 ]]; then
json_docs="[]"
else
json_docs=$(for d in "${docs[@]}"; do printf '"%s",' "$(json_escape "$d")"; done)
json_docs="[${json_docs%,}]"
fi
printf '{"FEATURE_DIR":"%s","AVAILABLE_DOCS":%s}\n' "$(json_escape "$FEATURE_DIR")" "$json_docs"
fi
else
# Text output
echo "FEATURE_DIR:$FEATURE_DIR"
echo "AVAILABLE_DOCS:"

# Show status of each potential document
check_file "$RESEARCH" "research.md"
check_file "$DATA_MODEL" "data-model.md"
check_dir "$CONTRACTS_DIR" "contracts/"
check_file "$QUICKSTART" "quickstart.md"

if $INCLUDE_TASKS; then
check_file "$TASKS" "tasks.md"
fi
fi
Loading