Guidance for coding agents working in the Termisu repository.
- This repo is primarily a Crystal library for terminal UIs.
- There are also Bun/TypeScript workspaces in
javascript/coreande2e. - Prefer changing the smallest surface area that solves the task.
- Follow existing architecture and naming before introducing new abstractions.
- Read
CLAUDE.mdfirst for architecture, command aliases, and project-specific patterns. - Check
CLAUDE.mdfor any repo-shipped agent guidance beyond this file. - Check
PROJECT_INDEX.mdfor a compact project overview. - Look at
spec/andexamples/before inventing new APIs or behaviors.
CLAUDE.mdexists at the repo root and contains repo-specific guidance.- No repo-local
.claude/instruction directory was found in this branch. - No
.cursor/rules/directory was found. - No
.cursorrulesfile was found. - No
.github/copilot-instructions.mdfile was found.
shards install
shards build ameba
shards build hace# Crystal library
bin/hace spec
bin/hace format
bin/hace format:check
bin/hace ameba
bin/hace ameba:fix
bin/hace all
# Single Crystal spec file
crystal spec spec/termisu/buffer_spec.cr
# Single Crystal spec example by line number
crystal spec spec/termisu/buffer_spec.cr:149
# Single Crystal spec by example name
crystal spec spec/termisu/buffer_spec.cr --example "forces full re-render"
# Examples
bin/hace demo
bin/hace showcase
bin/hace animation
bin/hace colors
bin/hace kmd
# C ABI
bin/hace ffi:build
bin/hace c:test
bin/hace c:check
# JS / E2E
bun install
bin/hace js:typecheck
bin/hace js:test
bin/hace js:check
bin/hace e2e:test
bin/hace e2e:check
# Docs site
bin/hace docs:build
bin/hace docs:serve- For Crystal, prefer
crystal spec path/to/file_spec.crfor a single file. - To run one example, use
crystal spec path/to/file_spec.cr:<line>. --examplealso works when the example name is stable.- Crystal specs mirror
src/structure underspec/termisu/. - For Bun tests in
javascript/core, runbun test tests/path/to/file.test.tsfromjavascript/core. - For E2E tests, inspect the
e2eworkspace and run the narrowest supportedtui-testtarget if the test runner accepts one; otherwise use the fullbin/hace e2e:testcommand.
- For Crystal-only changes: run
bin/hace format,bin/hace ameba, thenbin/hace spec. - For JS workspace changes: run the relevant
bin/hace js:*orbin/hace e2e:*commands. - Before finishing a non-trivial change, prefer
bin/hace allif the touched areas are covered by it. - If you touch C ABI files, also run
bin/hace c:checkandbin/hace c:test.
src/termisu/contains the main Crystal implementation.src/termisu.cris the public entry point and requires the internal tree.spec/termisu/mirrors thesrc/termisu/structure.spec/support/,spec/shared/, andexamples/are the best behavior references.javascript/core/contains Bun FFI bindings;e2e/contains terminal integration tests.
- The repo currently has a single primary maintainer: omarluq. Use the map below as routing guidance for where to look first, which files usually move together, and which changes deserve extra care before handing work back.
- Public Facade: maintainer
@omarluq; start insrc/termisu.cr,src/termisu/terminal.cr, and top-level public types such assrc/termisu/color.crandsrc/termisu/attribute.cr. - Terminal State + Low-Level I/O: maintainer
@omarluq; inspectsrc/termisu/terminal/,src/termisu/tty.cr, andsrc/termisu/termios.crtogether because mode changes, cleanup, and fd ownership are tightly coupled. - Rendering Core: maintainer
@omarluq; changes usually spansrc/termisu/buffer.cr,src/termisu/render_state.cr,src/termisu/cell.cr, and cursor/color state. - Input Reading: maintainer
@omarluq; start withsrc/termisu/reader.crand adjacent terminal backend code before changing buffering, blocking, or read-loop behavior. - Input Parsing: maintainer
@omarluq; focus onsrc/termisu/input/parser.cr,src/termisu/input/key.cr, andsrc/termisu/input/modifier.cr; confirm behavior against existing parser specs before changing escape handling. - Event System: maintainer
@omarluq; readsrc/termisu/event/loop.cr,src/termisu/event.cr,src/termisu/event/source*.cr, and event payload types as one subsystem. - Poller Backends / Cross-Platform Timing: maintainer
@omarluq; inspectsrc/termisu/event/poller/,src/termisu/event/source/timer.cr, andsrc/termisu/event/source/system_timer.cr; preserve platform branches and shutdown semantics. - Terminfo + Capability Layer: maintainer
@omarluq; start insrc/termisu/terminfo/; parser, database lookup, builtins, andtparmlogic should be treated as one compatibility surface. - Logging: maintainer
@omarluq; keepsrc/termisu/log.crlow-noise and best-effort, and avoid introducing logging that changes terminal timing or cleanup paths. - FFI / C ABI: maintainer
@omarluq; checksrc/c/,include/, andspec/c/together, then run the dedicatedbin/hace ffi:build,bin/hace c:check, andbin/hace c:testcommands when behavior changes. - JavaScript/Bun Wrapper: maintainer
@omarluq; usejavascript/core/as the source of truth for Bun bindings and keep it aligned with the Crystal/C ABI surface. - E2E / PTY Testing: maintainer
@omarluq; inspecte2e/and related docs before changing terminal sequencing, async timing, or snapshot-style expectations. - Examples: maintainer
@omarluq; keepexamples/representative of supported public APIs, especially when changing ergonomics or output behavior. - Specs / Shared Test Infra: maintainer
@omarluq; prefer mirrored specs underspec/termisu/and reuse helpers fromspec/support/andspec/shared/before adding new scaffolding. - Docs / Contributor Guidance: maintainer
@omarluq; updateAGENTS.md,CLAUDE.md,PROJECT_INDEX.md,README.md,CONTRIBUTING.md, anddocs/ordocs-web/when public behavior or contributor workflow changes.
- Use 2 spaces;
.editorconfigenforces this for*.crfiles. - Run
bin/hace formatinstead of manual formatting. - Keep lines ideally under 100 chars; 120 is the practical upper bound.
- Add a blank line after
requirestatements. - Prefer one top-level class/struct/module per file.
- Keep file paths aligned with namespaces, e.g.
src/termisu/event/source.cr->Termisu::Event::Source.
- Prefer relative
requirestatements insidesrc/termisu*. - Aggregator files commonly use glob requires such as
require "./termisu/*". - Platform-specific code uses compile-time branches and conditional
requires. - Do not reorder requires gratuitously if file load order matters.
- Prefer explicit type annotations on public methods and important ivars.
- Use
Int32,UInt8,UInt64,Bool, andTime::Spanintentionally; match surrounding code. - Use nilable types (
Foo?) only when absence is a real state. - Prefer value types (
struct) for small immutable-ish data like cells, colors, cursors, or events. - Use classes for resource-owning components like terminals, readers, and event sources.
- Return
Boolfor validation-style APIs when failure is expected and non-exceptional. - Use keyword arguments for multi-argument APIs when they improve clarity.
- Files use
snake_case.cr. - Types, enums, and modules use
PascalCase. - Methods and variables use
snake_case. - Predicate methods end in
?and should returnBool. - Setters end in
=. - Constants are usually
SCREAMING_SNAKE_CASEin the current codebase. - Keep all public types under the
Termisu::namespace.
- Use exceptions for true failure states and invalid system interactions.
- Reuse repo-specific errors like
Termisu::Error,Termisu::IOError, andTermisu::ParseErrorwhen they fit. - Preserve underlying context in error messages; include the failing operation.
- Use
ensurefor terminal cleanup, mode restoration, file closing, and similar lifecycle safety. - Handle expected channel shutdowns explicitly, e.g.
rescue Channel::ClosedErrorin event fibers. - Avoid silent rescue unless the code is intentionally best-effort, like shutdown/log flushing.
- Event sources should use
Atomic(Bool)or similar patterns for running state. - Named fibers are preferred for long-lived background work.
- Check running state in loops so shutdown stays clean.
- Be careful with terminal mode transitions; restore state on every exit path.
- Rendering is diff-based and optimized; preserve buffer invariants when editing buffer logic.
- Add or update specs with every behavioral change.
- Keep spec files colocated by mirrored path and name them
*_spec.cr. - Test public behavior first; add focused regression specs for bugs.
- Reuse helpers from
spec/support/and shared patterns fromspec/shared/. - Use
MockRendererand other test doubles already present before adding new ones.
- Pre-commit hooks are managed by Lefthook via
lefthook.yml. - Hooks run Crystal formatting/linting and relevant E2E formatting/linting.
- Update docs or examples when public behavior changes.
- Start with the narrowest relevant tests.
- Prefer existing patterns over novel abstractions.
- When touching low-level rendering, reader, termios, or event code, read adjacent files first.
- When unsure about intended API behavior, trust
examples/andspec/over assumptions. - If a task only affects
docs-web/, also consultdocs-web/AGENTS.md.
IMPORTANT: This project uses bd (beads) for ALL issue tracking. Do NOT use markdown TODOs, task lists, or other tracking methods.
- Dependency-aware: Track blockers and relationships between issues
- Git-friendly: Dolt-powered version control with native sync
- Agent-optimized: JSON output, ready work detection, discovered-from links
- Prevents duplicate tracking systems and confusion
Check for ready work:
bd ready --jsonCreate new issues:
bd create "Issue title" --description="Detailed context" -t bug|feature|task -p 0-4 --json
bd create "Issue title" --description="What this issue is about" -p 1 --deps discovered-from:bd-123 --jsonClaim and update:
bd update <id> --claim --json
bd update bd-42 --priority 1 --jsonComplete work:
bd close bd-42 --reason "Completed" --jsonbug- Something brokenfeature- New functionalitytask- Work item (tests, docs, refactoring)epic- Large feature with subtaskschore- Maintenance (dependencies, tooling)
0- Critical (security, data loss, broken builds)1- High (major features, important bugs)2- Medium (default, nice-to-have)3- Low (polish, optimization)4- Backlog (future ideas)
- Check ready work:
bd readyshows unblocked issues - Claim your task atomically:
bd update <id> --claim - Work on it: Implement, test, document
- Discover new work? Create linked issue:
bd create "Found bug" --description="Details about what was found" -p 1 --deps discovered-from:<parent-id>
- Complete:
bd close <id> --reason "Done"
bd automatically syncs via Dolt:
- Each write auto-commits to Dolt history
- Use
bd dolt push/bd dolt pullfor remote sync - No manual export/import needed!
- ✅ Use bd for ALL task tracking
- ✅ Always use
--jsonflag for programmatic use - ✅ Link discovered work with
discovered-fromdependencies - ✅ Check
bd readybefore asking "what should I work on?" - ❌ Do NOT create markdown TODO lists
- ❌ Do NOT use external issue trackers
- ❌ Do NOT duplicate tracking systems
For more details, see README.md and docs/QUICKSTART.md.
When ending a work session, you MUST complete ALL steps below. Work is NOT complete until git push succeeds.
MANDATORY WORKFLOW:
-
File issues for remaining work - Create issues for anything that needs follow-up
-
Run quality gates (if code changed) - Tests, linters, builds
-
Update issue status - Close finished work, update in-progress items
-
PUSH TO REMOTE - This is MANDATORY:
git pull --rebase bd dolt push git push git status # MUST show "up to date with origin" -
Clean up - Clear stashes, prune remote branches
-
Verify - All changes committed AND pushed
-
Hand off - Provide context for next session
CRITICAL RULES:
- Work is NOT complete until
git pushsucceeds - NEVER stop before pushing - that leaves work stranded locally
- NEVER say "ready to push when you are" - YOU must push
- If push fails, resolve and retry until it succeeds
Use 'bd' for task tracking
This repo uses beads_viewer (bv) as a read-only sidecar for graph-aware triage on the existing beads data in .beads/.
bv is a graph-aware triage engine for Beads projects. Use it to inspect priorities, blockers, and dependency structure without replacing the repo's bd write/update workflow.
Scope boundary: use bv for read-only triage and graph analysis; use bd for creating, updating, claiming, and closing issues.
CRITICAL: Use ONLY --robot- flags with the repo database, e.g. bv --db .beads --robot-triage. Never run bare bv; it launches an interactive TUI that blocks your session.*
bv --db .beads --robot-triage is the main entry point. It returns a compact triage view with ranked recommendations, quick wins, blockers, project health, and suggested follow-up commands.
bv --db .beads --robot-triage
bv --db .beads --robot-next
bv --db .beads --robot-plan
bv --db .beads --robot-alerts
bv --db .beads --robot-suggest
bv --db .beads --robot-triage --format toonAccurate dependencies and labels materially improve bv results, so keep issue links and metadata tidy through the normal bd workflow.
quick_ref: at-a-glance counts + top 3 picksrecommendations: ranked actionable items with scores, reasons, unblock infoquick_wins: low-effort high-impact itemsblockers_to_clear: items that unblock the most downstream workproject_health: status/type/priority distributions, graph metricscommands: copy-paste shell commands for next steps
| Command | Returns |
|---|---|
--robot-plan |
Parallel execution tracks with unblocks lists |
--robot-priority |
Priority misalignment detection with confidence |
--robot-insights |
Full metrics: PageRank, betweenness, HITS, eigenvector, critical path, cycles, k-core |
--robot-alerts |
Stale issues, blocking cascades, priority mismatches |
--robot-suggest |
Hygiene: duplicates, missing deps, label suggestions, cycle breaks |
--robot-diff --diff-since <ref> |
Changes since ref: new/closed/modified issues |
--robot-graph [--graph-format=json|dot|mermaid] |
Dependency graph export |
bv --db .beads --robot-plan --label backend # Scope to label's subgraph
bv --db .beads --robot-insights --as-of HEAD~30 # Historical point-in-time
bv --db .beads --recipe actionable --robot-plan # Pre-filter: ready to work (no blockers)
bv --db .beads --recipe high-impact --robot-triage # Pre-filter: top PageRank scores