Project: Contrabass โ Go reimplementation of OpenAI's Symphony using Charm TUI stack
Module: github.com/junhoyeo/contrabass
Go Version: 1.25.0
Repository: https://github.com/junhoyeo/contrabass
contrabass/
โโโ cmd/contrabass/ # CLI entry point
โโโ internal/
โ โโโ config/ # Configuration parsing
โ โโโ tracker/ # State tracking
โ โโโ workspace/ # Workspace management
โ โโโ agent/ # Agent orchestration
โ โโโ orchestrator/ # Orchestration logic
โ โโโ tui/ # Terminal UI components
โ โโโ logging/ # Logging utilities
โ โโโ types/ # Shared type definitions
โโโ docs/ # Documentation
โโโ testdata/ # Test fixtures
- bubbletea v2 โ TUI framework
- bubbles v2 โ Reusable components
- lipgloss v2 โ Styling and layout
CRITICAL: Use vanity import paths:
- โ
charm.land/bubbletea/v2 - โ
charm.land/bubbles/v2 - โ
charm.land/lipgloss/v2 - โ
github.com/charmbracelet/...(WRONG)
- Cobra โ CLI framework
- Fang v0.4.4 โ Experimental (cosmetics only, not stable)
- fsnotify โ File system watching
- osteele/liquid โ Template rendering
- testify โ Testing assertions
<type>(<scope>): <description>
| Type | Purpose |
|---|---|
feat |
New feature or capability |
fix |
Bug fix |
refactor |
Code restructuring without behavior change |
docs |
Documentation only |
test |
Adding or updating tests |
chore |
Build, tooling, dependency updates |
perf |
Performance improvement |
Use the Go package name as the scope:
| Scope | Package |
|---|---|
config |
internal/config |
tracker |
internal/tracker |
workspace |
internal/workspace |
agent |
internal/agent |
orchestrator |
internal/orchestrator |
tui |
internal/tui |
logging |
internal/logging |
types |
internal/types |
cli |
cmd/contrabass |
project |
Project-wide (go.mod, .gitignore, CI, etc.) |
docs |
Documentation files |
- Atomic commits โ One logical change per commit
- Description โ Lowercase, imperative mood, no period at end
- Length โ Keep description under 72 characters
- No metadata โ No internal review labels or metadata in commit messages
- No trailing punctuation โ Description ends without period
feat(config): add WORKFLOW.md parser with YAML front matter support
test(orchestrator): port state machine transition tests from Elixir
fix(agent): handle JSON-RPC error code -32001 for server overload
refactor(tui): split model into header and table sub-components
docs(project): add AGENTS.md with commit convention
chore(project): initialize go.mod with Charm v2 dependencies
perf(tracker): cache workspace state to reduce file I/O
CRITICAL: When resolving conflicts or updating PR branches, you MUST preserve the original commit history. Every commit represents a logical unit of work and its message documents WHY the change was made.
When a PR branch has diverged from main and needs to incorporate main's changes:
- Use
git merge mainINTO the PR branch โ this creates a merge commit that preserves both histories - NEVER squash PR commits โ squashing destroys the granular history of the PR's development
- NEVER create a new branch and cherry-pick/squash โ this rewrites history and loses the original commit SHAs
- NEVER use
git rebaseon shared/pushed PR branches without explicit owner permission โ rebase rewrites commit SHAs
git checkout <pr-branch>
git merge main --no-edit
# resolve conflicts
git add -A
git commit # merge commit is created automatically
git push origin <pr-branch> --force # only if branch was previously force-pushed
The result should be:
- All original PR commits preserved with their original SHAs
- A single merge commit on top that brings in main's changes
- The merge commit resolves any conflicts
git rebase mainon a PR branch (rewrites all commit SHAs)- Creating a new branch from main and squash-merging PR changes into it (destroys history)
git reset --hardon a PR branch to a different base (destroys commits)- Any operation that reduces N commits into 1 commit without explicit permission
- NEVER force-push to
mainโ this is always destructive - Force-push to PR branches is acceptable ONLY when:
- Restoring previously destroyed history (fixing a mistake)
- The PR owner explicitly requests it
- The branch has already been force-pushed before (not the first push)
- Testing: Table-driven tests with testify assertions
- Error handling: Explicit error returns, no panic in libraries
- Context: Use
context.Contextfor cancellation and timeouts - Concurrency: goroutines +
errgroup+context.WithCancelfor supervision
- Use Lip Gloss v2 for styling and layout
- IMPORTANT:
View()returnsstring(notio.Writer) - REMOVED:
AdaptiveColorโ use explicit colors orlipgloss.Color() - Use Lip Gloss v2 table for static rendering
- Use Bubbles v2 components where available
- NOT Bubbles Table (interactive) โ use Lip Gloss table instead
- Follow Elm architecture: Model, Update, View
- Use
tea.Cmdfor side effects - Proper cleanup in
Quitcommand
- Framing: JSONL (JSON Lines) โ one JSON object per line
- NOT Content-Length headers
- Error codes: Handle
-32001(server overload) gracefully
- Fang v0.4.4: Experimental โ use for cosmetics only, not core logic
- fsnotify: For file system watching
- osteele/liquid: For template rendering
- testify: For assertions in tests
- Strategy: Table-driven tests
- Assertions: Use testify (
assert,require) - Command:
go test ./... - Fixtures: Place test data in
testdata/
- Keep
docs/directory up-to-date - Use Markdown for all documentation
- Link to relevant code sections
- Document architectural decisions in
AGENTS.mdordocs/
- Charm v2 released stable on Feb 24, 2026
- Vanity import paths are the official way to import
- All v2 APIs are stable and recommended
- Fang v0.4.4 is experimental
- Use only for cosmetics (styling, formatting)
- Do not rely on Fang for core functionality
View()returnsstring(breaking change from v1)AdaptiveColorremoved โ use explicit colors- Table component is static (not interactive)
- Uses JSONL framing (one JSON object per line)
- No Content-Length headers
- Handle error code
-32001(server overload)
- Use
errgroup.Groupfor managing goroutines - Use
context.WithCancelfor graceful shutdown - Always propagate context through function calls
When working on this codebase:
- Is this a Charm v2 import? Use vanity paths (
charm.land/...) - Is this TUI rendering? Use Lip Gloss v2 (static), not Bubbles Table
- Is this a test? Use table-driven tests with testify
- Is this concurrent? Use
errgroup+context.WithCancel - Is this a commit message? Follow the convention above