Skip to content
Merged
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
123 changes: 95 additions & 28 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,56 +1,123 @@
---
description: Agent instructions for the subtrack monorepo
---

# subtrack

Monorepo for **subtrack** — a CLI tool to manage subscription services from the terminal.

## Agent Role

You are a subtrack agent. Your primary responsibilities in this repository are:

- Understanding the full monorepo structure and how packages relate
- Implementing features and fixing bugs in the CLI tool (`subtrack/`)
- Maintaining code quality, type safety, and test coverage
- Following project conventions (ESM, TypeScript strict, `sql.js`, `gunshi`)
- Knowing when to load project-specific skills for detailed guidance

## Repository Structure

```
.
├── subtrack/ # CLI tool (Node.js/TypeScript, published as npm package)
├── docs/ # Documentation site (SvelteKit)
├── .agents/ # OpenCode agent and skill definitions
├── flake.nix # Nix devShell / CI shell
├── subtrack/ # CLI tool (Node.js/TypeScript, published as npm package)
│ ├── src/ # Source code
│ ├── dist/ # Build output (dist/index.mjs)
│ ├── package.json # Dependencies and scripts
│ └── tsconfig.json # TypeScript configuration
├── docs/ # Documentation site (SvelteKit)
├── .agents/skills/ # OpenCode skill definitions
├── flake.nix # Nix devShell / CI shell
└── pnpm-workspace.yaml
```

## Package Management
**Key**: All application code lives under `subtrack/`. The monorepo root has no dependencies of its own.

## Design Tenets

1. **CLI-native** — Everything is driven from the terminal. No web UI, no daemon, no TUI framework.
2. **SQLite persistence** — Data is stored locally via `sql.js` (WASM SQLite). No external database servers.
3. **Layer separation** — Code is organized into strict layers (entry → commands → DB → display). Cross-layer concerns are mediated, not mixed.
4. **Interactive by default, scriptable by flag** — Commands prompt interactively when invoked bare, but accept flags for automation.
5. **Portable** — Works on Linux/macOS. Single binary via npm package. No platform-specific dependencies.

## Architecture Overview

- Use `pnpm add <package>` instead of `npm install <package>` or `bun add <package>`
- Use `pnpm remove <package>` instead of `npm uninstall <package>` or `bun remove <package>`
- Use `pnpm update` instead of `npm update` or `bun update`
- Use `pnpm run <script>` or `pnpm <script>` instead of `npm run` or `bun run`
- Use `pnpmx <package>` instead of `npx` or `bunx`
The CLI tool (`subtrack/`) uses `gunshi` for command routing and follows a multi-layer architecture:

## Root Commands
| Layer | File | Responsibility |
| ----------- | ------------------- | ----------------------------------- |
| Entry | `src/index.ts` | Command definitions (gunshi), routing |
| Commands | `src/commands.ts` | Command handlers, workflow logic |
| Database | `src/db.ts` | SQLite CRUD, schema, persistence |
| Display | `src/display.ts` | Table rendering, formatting |
| Prompts | `src/prompts.ts` | Input validation, interactive prompts |
| Payment | `src/payment.ts` | Payment/summary calculations |
| FX | `src/fx.ts` | Exchange rate fetching & conversion |
| Usage | `src/usage.ts` | LLM API usage tracking |

For **detailed implementation guidance** (DB schema, testing patterns, import style, dependency reference), load the `subtrack-rules` skill.

## Available Skills

This repository defines skills under `.agents/skills/`. Load them via the `skill` tool when the task matches:

| Skill | When to load |
|---|---|
| `subtrack-rules` | Working on source code, running tests, managing dependencies — full project conventions |
| `subtrack-commit` | Committing, pushing, or creating a PR |
| `bug-fixes` | Diagnosing test failures, debugging runtime errors, fixing type errors |

All 3 skills are also available automatically via the agent system prompt.

## Key Conventions

- **Runtime**: Node.js (>=22), **not** Bun or Deno
- **Language**: TypeScript (strict mode, ESM, `verbatimModuleSyntax`)
- **Database**: `sql.js` (SQLite via WASM) — **not** `better-sqlite3` or `bun:sqlite`
- **CLI**: `gunshi` — **not** `commander` (despite what old docs may say)
- **Package manager**: `pnpm` — **not** npm or bun
- **Local imports**: use `.ts` extension (`import { x } from "./foo.ts"`)
- **Node built-ins**: use `node:` prefix (`node:fs`, `node:path`, `node:os`)
- **Type imports**: use `type` prefix (`import type { X } from "./foo.ts"`)
- **No semicolons** in imports/exports
- **Prices**: stored as integers (smallest unit — JPY no decimal, USD in cents)
- **DB transactions**: use `BEGIN TRANSACTION` / `COMMIT` / `ROLLBACK` for multi-step writes
- **PRAGMA**: `PRAGMA foreign_keys = ON` at connection time

## Quick Reference

```bash
pnpm install # install all workspace dependencies
pnpm build # build all packages (pnpm -r build)
pnpm test # test all packages (pnpm -r test)
```

## Nix DevShell

```bash
nix develop # enter devShell (node, pnpm, typos, typescript, nixfmt)
pnpm start # run CLI in dev mode (tsx src/index.ts)
nix develop # enter devShell
nix fmt # format nix files (nixfmt-rfc-style)
```

## Key Conventions
Available CLI commands (run `subtrack --help` in the package for the full list):

- **Runtime**: Node.js, **NOT** Bun or Deno
- **Language**: TypeScript (strict mode, ESM, `verbatimModuleSyntax`)
- **Database**: `sql.js` (SQLite via WASM), **NOT** `better-sqlite3` or `bun:sqlite`
- **Node built-ins**: Use `node:` prefix (`node:fs`, `node:path`, `node:os`)
- **Local imports**: Use `.ts` extension (`import { x } from "./foo.ts"`)
- **Type imports**: Use `type` prefix (`import type { X } from "./foo.ts"`)
- **No semicolons** in imports/exports
- **API**: Prefer native `fetch` for HTTP, native `WebSocket` for WebSocket
| Command | Description |
|---|---|
| `subtrack list` | List all subscriptions |
| `subtrack add` | Add a subscription |
| `subtrack edit [id]` | Edit a subscription |
| `subtrack delete [ids...]` | Delete subscriptions |
| `subtrack tags <names...>` | Filter by tags (AND logic) |
| `subtrack tag list\|rename\|delete\|prune` | Manage tags |
| `subtrack export csv\|json\|md` | Export subscriptions |
| `subtrack import <file>` | Import from CSV |
| `subtrack summary` | Show subscription summary |
| `subtrack backup [destination]` | Backup database |
| `subtrack restore [file]` | Restore database |
| `subtrack payment [period]` | Show payment totals |
| `subtrack usage add\|list\|delete\|refresh` | Track LLM API usage |

## Environment Variables

| Variable | Description |
| ------------------ | ------------------------------------------------- |
| Variable | Description |
|---|---|
| `SUBSC_CLI_DB_DIR` | Override database directory (default: `~/.config/subtrack`) |

## Links
Expand Down
44 changes: 29 additions & 15 deletions subtrack/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ CLI tool to manage subscription services from the terminal. Node.js + TypeScript

## Tech Stack

- **Runtime**: Node.js (not Bun or Deno)
- **Runtime**: Node.js (>=22, not Bun or Deno)
- **Language**: TypeScript (strict mode, ESM, `verbatimModuleSyntax`)
- **Database**: `sql.js` (SQLite via WASM)
- **CLI**: `commander`
- **CLI**: `gunshi`
- **Prompts**: `@inquirer/prompts`
- **Logging**: `consola`
- **Tables**: `cli-table3`
- **Colors**: `picocolors`
- **Build**: `tsdown`
- **Test**: `vitest`

Expand All @@ -36,15 +37,23 @@ CLI tool to manage subscription services from the terminal. Node.js + TypeScript
- Mock `consola` via `consola.mockTypes()`
- Mock `globalThis.fetch` for FX rate API

## Architecture (4 layers)
## Architecture

| Layer | File | Responsibility |
|---|---|---|
| Entry | `src/index.ts` | CLI definition (commander), command routing |
| Commands | `src/commands.ts` | Command handlers, workflow logic |
| Database | `src/db.ts` | SQLite CRUD, schema, persistence |
| Display | `src/display.ts` | Table rendering, FX rate conversion |
| Prompts | `src/prompts.ts` | Input validation, interactive prompts |
| File | Responsibility |
|---|---|
| `src/index.ts` | CLI definition (gunshi), command routing |
| `src/commands.ts` | Command handlers, workflow logic |
| `src/db.ts` | SQLite CRUD, schema, persistence |
| `src/display.ts` | Table rendering, formatting |
| `src/prompts.ts` | Input validation, interactive prompts |
| `src/payment.ts` | Payment/summary calculations |
| `src/fx.ts` | Exchange rate fetching & conversion |
| `src/usage.ts` | LLM API usage tracking |
| `src/export.ts` | CSV/JSON/MD export |
| `src/import-csv.ts` | CSV import |
| `src/crypto.ts` | Backup encryption |
| `src/pricing.ts` | Pricing/litellm integration |
| `src/types.ts` | Shared types |

## Key Conventions

Expand All @@ -53,7 +62,6 @@ CLI tool to manage subscription services from the terminal. Node.js + TypeScript
- **Type imports**: `type` prefix (`import type { X } from "./foo.ts"`)
- **No semicolons** in imports/exports
- **Prices**: integers (smallest unit — JPY no decimal, USD cents)
- **Cycles**: weekly / bi-weekly / monthly / quarterly / semi-annual / yearly
- **DB**: `sql.js` with `PRAGMA foreign_keys = ON`, use transactions for multi-step writes

## Environment Variables
Expand All @@ -68,8 +76,14 @@ CLI tool to manage subscription services from the terminal. Node.js + TypeScript
|---|---|
| `subtrack list` | List all subscriptions |
| `subtrack add` | Add a subscription |
| `subtrack delete` | Delete subscriptions (interactive) |
| `subtrack tags <taglist...>` | Filter by tags |
| `subtrack backup <destination>` | Backup database |
| `subtrack edit [id]` | Edit a subscription |
| `subtrack delete [ids...]` | Delete subscriptions |
| `subtrack tags <names...>` | Filter by tags (AND logic) |
| `subtrack tag list\|rename\|delete\|prune` | Manage tags |
| `subtrack export csv\|json\|md` | Export subscriptions |
| `subtrack import <file>` | Import from CSV |
| `subtrack summary` | Show subscription summary |
| `subtrack backup [destination]` | Backup database |
| `subtrack restore [file]` | Restore database |
| `subtrack payment [period]` | Show payment totals |
| `subtrack export csv` | Export subscriptions as CSV |
| `subtrack usage add\|list\|delete\|refresh` | Track LLM API usage |
Loading