Get set up and ship code in 5 minutes. No ceremony.
git clone https://github.com/thevibeworks/ccx.git
cd ccx
make build # Builds ./bin/ccx
make test # Runs tests
./bin/ccx --helpRequirements: Go 1.24+ (pure Go, no CGO/C compiler needed)
make test # All tests
go test ./internal/parser/... # Specific package
go test -v -run TestFoo # Specific testcmd/ccx/main.go Entry point
internal/
├── cmd/ Cobra commands
│ ├── root.go
│ ├── projects.go
│ ├── sessions.go
│ ├── view.go
│ ├── export.go
│ └── web.go
├── parser/ JSONL parsing + tree building
├── render/ Output formats (HTML, MD, Org)
├── web/ HTTP server + templates
├── db/ SQLite persistence (stars, cache)
└── config/ Configuration paths
Pattern:
- Commands in
internal/cmd/ - Core logic in
internal/{domain}/ - No external dependencies in parser (stdlib only)
Example: Adding ccx stats
- Create the command file:
touch internal/cmd/stats.go- Write the command:
package cmd
import "github.com/spf13/cobra"
var statsCmd = &cobra.Command{
Use: "stats",
Short: "Show session statistics",
RunE: runStats,
}
func init() {
rootCmd.AddCommand(statsCmd)
}
func runStats(cmd *cobra.Command, args []string) error {
// Implementation
return nil
}- Test it:
make build && ./bin/ccx stats- Add to
internal/render/:
// internal/render/csv.go
func RenderCSV(session *parser.Session) ([]byte, error) {
// Implementation
}- Register in export command (
internal/cmd/export.go)
Before submitting:
make testpassesmake buildsucceeds- Manual test with real Claude Code sessions
PR description:
What: Added `ccx stats` command
Why: Users want to see token usage across sessions
Tested: Ran against my ~/.claude sessions
No templates. Just tell us what you did and why.
- Full-text search within session content
- Session comparison/diff view
- More export formats (PDF, EPUB)
- MCP server mode
- Session replay
- Custom tagging
- Modifying Claude Code sessions (read-only by design)
- Syncing to cloud services
- Anything that requires network access by default
Follow Go conventions:
gofmtyour code- Meaningful names:
sessionIDnotsid - Comments explain WHY, not WHAT
- If it needs a comment to understand WHAT it does, refactor it
Error messages:
BAD: return fmt.Errorf("error")
GOOD: return fmt.Errorf("failed to parse session %s: %w", path, err)Test logic, not I/O.
// Good - tests parsing logic
func TestParseMessage_ExtractsContent(t *testing.T) {
msg := parseMessage(`{"type":"user","content":"hello"}`)
if msg.Content != "hello" {
t.Errorf("expected hello, got %s", msg.Content)
}
}
// Bad - tests filesystem
func TestReadSession_ReadsFile(t *testing.T) {
session := ReadSession("/path/to/session.jsonl")
// ...
}Use testdata/ for fixture files. Keep them minimal.
Open an issue. We're friendly, just direct.
Inspired by Simon Willison's claude-code-transcripts. Rebuilt in Go.