This file is for Claude Code (or any AI assistant) working on this codebase. It describes the project structure, how to build and test, and how to extend the system.
ITKdev Claude Code compiles to a single binary (icc) that wraps Claude Code with quality hooks, persistent memory, context management, and spec-driven development support.
make build # Build bin/icc for current platform
make test # Run all tests (go test ./...)
make lint # Run golangci-lint
make release # Cross-compile for macOS + Linux (arm64/amd64)
make all # Build web viewer then compile binaryVersion is injected at build time via -ldflags. The dev version is used for local builds.
cmd/icc/main.go # Entry point — calls cli.Execute()
internal/
cli/ # All CLI commands (cobra)
root.go # Root command, --json global flag
run.go # icc run — launches Claude Code
serve.go # icc serve — standalone console server
hook.go # icc hook <name> — dispatcher entry
install.go # icc install — multi-step installer
worktree.go # icc worktree subcommands
session.go # icc session list
context.go # icc check-context
sendclear.go # icc send-clear
registerplan.go # icc register-plan
greet.go # icc greet
statusline.go # icc statusline
config/
branding.go # ★ Product name, env prefix, config dir name
constants.go # Version, default port, default log level
config.go # Runtime config from env vars
paths.go # Derived paths (~/.icc/db/, sessions/, logs/)
hooks/
dispatcher.go # Hook registry and dispatch (name → handler)
protocol.go # Hook input/output JSON protocol (stdin/stdout)
context_monitor.go # Context usage tracking
file_checker.go # Language-aware lint/format
tdd_enforcer.go # TDD order enforcement
tool_redirect.go # Block/redirect tool calls
branch_guard.go # Enforce branch workflow (no commits to main)
spec_stop_guard.go # Prevent premature stop during /spec
spec_plan_validator.go # Plan file structure validation
spec_verify_validator.go # Verification result validation
notify.go # Desktop notifications
checkers/
checker.go # Checker interface
python.go # ruff + basedpyright
typescript.go # prettier + eslint + tsc
golang.go # gofmt + golangci-lint
console/
server.go # HTTP server, route registration, lifecycle
mcp.go # MCP server with memory tools
sse.go # Server-Sent Events broadcaster
handlers.go # HTTP handlers (observations, sessions, plans, etc.)
handlers_search.go # Search-specific handlers
handlers_session.go # Session-specific handlers
context/
builder.go # Build startup context from observations
token.go # Token estimation
db/
database.go # SQLite connection, Open(), Close()
migrations.go # Schema migrations (run on Open)
observations.go # Observation CRUD
sessions.go # Session CRUD
summaries.go # Summary CRUD
plans.go # Plan CRUD
prompts.go # Prompt storage
search/
orchestrator.go # Hybrid search coordinator
vector_search.go # Embedding-based semantic search
embedding.go # Local embedding generation
retention.go # Background cleanup scheduler
formatter.go # Result formatting
session/
manager.go # Session lifecycle
runner.go # Claude Code process runner
client.go # HTTP client for console API
context_check.go # Read context percentage from session dir
sendclear.go # Clear signal + continuation prompt
worktree/
manager.go # Create, detect, diff, sync, cleanup, status
stash.go # Auto-stash/restore for dirty trees
merge.go # Squash merge logic
installer/
installer.go # Step orchestrator with rollback
ui.go # Terminal UI (banner, progress, summary)
steps/
prerequisites.go # Check git, Claude Code
dependencies.go # Install optional tools
shell_config.go # Add to .zshrc/.bashrc
claude_files.go # Create .claude/ directory
config_files.go # Write settings, hooks, MCP config
vscode.go # VS Code recommendations
finalize.go # Final verification
statusline/
formatter.go # JSON→formatted status line
tips.go # Contextual tips
updater/
checker.go # Check GitHub releases for updates
updater.go # Self-update binary
notify/
notify.go # Cross-platform desktop notifications
assets/
embed.go # embed.FS for rules, commands, agents, viewer
extract.go # Extract embedded files to disk
assets/ # Source files that get embedded
rules/ # Markdown rule files
commands/ # Spec commands
agents/ # Agent definitions
viewer/ # Web viewer static files
docs/
plan.md # Original implementation plan
usage.md # User-facing usage documentation
All product name references derive from internal/config/branding.go:
BinaryName = "icc" // CLI name
DisplayName = "ITKdev Claude Code" // Human-readable
EnvPrefix = "ICC" // Env var prefix (ICC_PORT, etc.)
ConfigDirName = ".icc" // ~/.icc/To rename, change these four constants, update go.mod module path, and BINARY_NAME in the Makefile.
Hooks self-register via init() functions. The dispatcher in hooks/dispatcher.go maintains a map[string]Hook registry. To add a new hook:
- Create
internal/hooks/my_hook.go - Implement the
Hookfunction signature:func(input *Input) error - Call
Register("my-hook", myHookFunc)in aninit()function - The hook is now callable via
icc hook my-hook
Hooks read JSON from stdin (ReadInput()) and write results via WriteOutput(), BlockWithError(), or ExitOK() — all defined in protocol.go.
Commands use cobra. Each command is in its own file under internal/cli/. The pattern:
- Create a
*cobra.Commandvariable - Add it to
rootCmd(or a parent command) in aninit()function - Use
jsonOutputglobal flag for--jsonsupport
Each installer step implements the Step interface:
type Step interface {
Name() string
Run(ctx *Context) error
Rollback(ctx *Context)
}Steps are in internal/installer/steps/. Add new steps there and wire them into cli/install.go.
HTTP routes are registered in console/server.go → registerRoutes(). Handlers are in handlers.go, handlers_search.go, and handlers_session.go. Add new routes by:
- Adding the handler method to
*Server - Registering the route in
registerRoutes()
SQLite via modernc.org/sqlite (pure Go, no CGO). Schema migrations are in db/migrations.go and run automatically on db.Open(). To add a new table:
- Add a migration function in
migrations.go - Register it in the migrations slice
- Create a new file for CRUD operations (e.g.,
db/my_table.go)
Static files in assets/ are embedded via embed.FS in internal/assets/embed.go. The Extract() function writes them to disk during icc install. The web viewer is served directly from the embedded FS.
Tests use the standard testing package with table-driven patterns. Most packages have *_test.go files alongside the source.
# All tests
go test ./...
# Specific package
go test ./internal/hooks/...
# Verbose (for debugging)
go test -v ./internal/db/...
# With race detector
go test -race ./...
# Coverage
go test -cover ./...Database tests use in-memory SQLite (:memory:). Console tests use httptest.NewRecorder().
| Dependency | Purpose |
|---|---|
github.com/spf13/cobra |
CLI framework |
github.com/go-chi/chi/v5 |
HTTP router |
modernc.org/sqlite |
Pure Go SQLite (no CGO) |
github.com/mark3labs/mcp-go |
MCP protocol server |
Keep dependencies minimal. Use stdlib where possible (net/http, log/slog, encoding/json, embed).
All changes go through pull requests. Direct pushes to main are blocked by a GitHub Ruleset (admins can bypass for emergencies only).
- Create a feature branch from
main:git checkout main && git pull git checkout -b feat/my-feature - Make changes and commit using Conventional Commits:
fix: ...— patch bump (bug fix)feat: ...— minor bump (new feature)feat!: ...or body containsBREAKING CHANGE:— major bump- Other prefixes (
chore:,docs:,refactor:,test:) — patch bump
- Push and open a PR against
main:git push -u origin feat/my-feature gh pr create
- Get at least 1 approving review before merging.
- Merge via GitHub (squash, rebase, or merge commit — all allowed). The feature branch is auto-deleted after merge.
This applies to both humans and AI agents (Claude Code). Always work in a feature branch and merge via PR.
Releases are fully automated via a single GitHub Actions workflow (.github/workflows/release.yml).
On every push to main (i.e., PR merge), the workflow:
- Finds the latest
v*tag - Analyzes commit messages since that tag using Conventional Commits:
feat!:orBREAKING CHANGE:→ major bumpfeat:→ minor bump- Everything else → patch bump
- Creates and pushes the new tag (e.g.,
v0.3.0→v0.3.1) - Builds 4 binaries (darwin/linux × arm64/amd64) via
make release - Creates a GitHub release with the binaries attached
- Dispatches a
repository_dispatchevent toyepzdk/homebrew-toolsto update the Homebrew formula
You can still manually tag for specific version jumps:
git tag v1.0.0
git push --tagsHOMEBREW_TAP_TOKEN — a GitHub Personal Access Token (PAT) with repo scope, stored in the repository's Settings → Secrets. Used to trigger the Homebrew tap update via the GitHub API.
- Create
internal/cli/mycommand.go - Define a
cobra.CommandwithUse,Short,RunE - In
init(), callrootCmd.AddCommand(myCmd)
- Create
internal/hooks/my_hook.go - Write the handler:
func myHook(input *Input) error { ... } - In
init(), callRegister("my-hook", myHook) - Add the hook to the hooks.json template in
installer/steps/config_files.go
- Create
internal/hooks/checkers/mylang.go - Implement the
Checkerinterface (Name, Extensions, Check) - Register it in an
init()function viaRegisterChecker()
- Add handler method to
*Serverinconsole/handlers.go(or a new handlers file) - Register the route in
console/server.go→registerRoutes() - Add tests in
console/server_test.go
- Create
internal/installer/steps/mystep.go - Implement
Stepinterface (Name, Run, Rollback) - Add it to the step list in
cli/install.go
- Add migration in
db/migrations.go - Create
db/mytable.gowith CRUD methods on*DB - Add tests in
db/database_test.go