pine

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 5, 2026 License: MIT

README ΒΆ

🌲 Pine

A git-native, local-first workspace for AI-assisted development.

CI Release Go Report Card

Pine keeps your bugs, features, epics, and project context as plain files inside your repository, so humans and AI agents (Claude Code, Codex, Gemini CLI, …) work from the same source of truth. No cloud, no accounts, no database β€” the repo is the database and git is the history.

A single binary gives you three surfaces over the same .pine/ folder:

  • a Beads-style CLI for tickets, dependencies, and epics from the terminal;
  • a beautiful local web UI (kanban board, markdown editor, attachments, search);
  • AI context/prompt generation so an agent understands the project instantly.

When an agent edits a ticket file on disk, the board updates live in your browser. When you drag a card, the file changes on disk. It is the same data, always.


Installation

Grab the binary for your platform from the Releases page. Each archive is a single self-contained pine binary with the web UI built in β€” no runtime dependencies.

macOS / Linux:

# pick the asset for your OS/arch, e.g. pine_0.1.0_darwin_arm64.tar.gz
tar -xzf pine_*_*.tar.gz
sudo mv pine /usr/local/bin/
pine --version

Windows: download the _windows_amd64.zip, extract pine.exe, and add it to your PATH.

With Go
go install github.com/underworld14/pine/cmd/pine@latest

This gives you the full CLI, HTTP API, and live sync. (The bundled web UI ships in the release binaries and make build only; a go install build serves a small placeholder page in place of the UI.)

Build from source

Requires Go 1.26+ and Node 20+.

git clone https://github.com/underworld14/pine
cd pine
make build            # builds the SvelteKit UI and embeds it into ./pine
./pine --version

Backend-only (no Node required) β€” serves a dev placeholder for the UI:

make build-dev

Quick start

cd your-repo
pine init                               # create .pine/
pine create --type bug --title "Login button dead" -p high -l login,ui
pine open                               # launch the web UI (localhost:3412)
The terminal workflow (Beads-style)

Everything works without leaving the shell; every read command takes --json for agents.

pine create --type epic --title "Auth system"
pine create --type feature --title "Login form" --parent EPIC-001 -p high
pine create --type bug --title "Button dead" --parent EPIC-001 --deps FEAT-001

pine list --blocked            # tickets waiting on dependencies (πŸ”’)
pine ready                     # actionable work: open and unblocked, most urgent first
pine dep tree BUG-001          # dependency tree
pine close FEAT-001            # β†’ BUG-001 becomes ready
pine show EPIC-001             # epic with child progress (1/2 done)
pine update BUG-001 --status doing

Dependency cycles are refused at write time. A ticket is blocked while any of its deps is not done, and ready otherwise β€” computed from the files, never stored, so agents editing files can't desync it.

AI context
pine context | pbcopy          # a full project briefing for your agent
pine prompt BUG-001            # a fix-request prompt for one ticket
pine export --format md        # all tickets as markdown (or --format json)

pine context includes a Conventions block that teaches the agent how to write back to .pine/ (edit status to move a ticket, use deps/parent, run pine ready/pine close).


How it stores data

Everything lives in .pine/ and is meant to be committed:

.pine/
  config.json           # project settings, ticket types, priorities, optimizer
  board.json            # kanban columns (statuses only β€” never ticket ids)
  tickets/
    BUG-001.md          # YAML frontmatter + markdown body
  attachments/
    BUG-001/login.webp  # optimized on ingest
  templates/            # bug.md, feature.md, epic.md
  prompts/fix.md        # the pine prompt template

A ticket file:

---
id: BUG-001
title: Login button not working
status: testing
priority: high
labels:
  - login
  - ui
deps:
  - FEAT-002
parent: EPIC-001
created: 2026-07-04T10:12:00Z
updated: 2026-07-04T11:00:00Z
---

# Description
...

The filename is the canonical id; frontmatter status decides which board column a ticket is in. Pine parses leniently β€” a malformed or agent-written file is surfaced as a read-only "degraded" ticket rather than lost, and pine doctor reports every problem (schema errors, dangling deps, dependency cycles, broken attachment references, orphaned directories, stray files).


Pine & git branches

Because .pine/ is committed alongside your code, tickets are versioned with your branches β€” exactly like source files. Switching branches changes which tickets you see: a ticket created and committed on dev won't appear while you're on main (it's not lost β€” it returns on dev, or when the branches merge). Uncommitted new tickets stay visible across branches, since git leaves untracked files alone.

This is a deliberate trade-off of the "everything is files" model. If you prefer a single global backlog, keep .pine/ mastered on your mainline (create/close tickets there and let them flow to feature branches via merge), or run Pine against a git worktree pinned to one branch.

Merge-safe IDs. New tickets get random, collision-resistant IDs like BUG-7f3k2a by default ("idStyle": "hash" in config.json), so two branches β€” or two AI agents β€” never mint the same ID. Prefer the classic sequential BUG-001? Set "idStyle": "sequential"; just note that concurrent branches can then choose the same number and clash on merge (pine doctor flags duplicates).

For contrast, Beads keeps issues global across branches by storing them in a Dolt database on a separate git ref rather than as files on your branches β€” a different point in the design space (global + cell-level merge, but not plain, hand-editable files).

Web UI

pine serve (or pine open) serves the UI on http://127.0.0.1:3412 (localhost only, with Host/Origin checks β€” no auth, no external access).

  • Dashboard β€” at-a-glance triage lists.
  • Board β€” drag & drop kanban; blocked cards show πŸ”’; cards glide + flash when an agent changes a file on disk.
  • Ticket β€” frontmatter controls, split markdown editor with a "changed on disk" conflict banner, dependency/epic chips, attachment grid + lightbox, and a one-click Copy AI prompt.
  • New issue in ≀10s: press c, type a title, paste a screenshot (⌘V), βŒ˜β†΅. Screenshots are downscaled and re-encoded to WebP on the way in.
  • Search (/) and a command palette (⌘K).

Attachments are optimized on upload: images are EXIF-oriented, downscaled to 2000px, and re-encoded to lossy WebP (kept only if smaller); videos pass through with an oversize warning. pine optimize back-fills files dropped in by hand.


VS Code extension

Prefer to stay in your editor? The Pine VS Code extension opens the same board in a VS Code tab β€” no terminal, no manual pine serve. Run Pine: Open Board and it starts Pine for you and embeds the UI; Pine: Create Bug / Create Feature add tickets from the command palette. It reuses the exact web UI, so live sync, attachments, and search all behave identically. See editors/vscode/README.md for details.


Development

make test        # Go unit + integration tests
make test-web    # frontend (vitest)
make e2e         # Playwright end-to-end (requires: cd web && npx playwright install)
make lint        # go vet

Tech

Go (cobra CLI, chi router, Bleve in-memory search, fsnotify watcher, SSE) with a SvelteKit 2 / Svelte 5 / Tailwind v4 UI embedded via go:embed. WebP encoding is pure-Go (no cgo), so the binary cross-compiles cleanly.

Contributing

Contributions of all kinds are welcome. See CONTRIBUTING.md for local setup and how to run the test suite, and please open an issue for bugs or feature ideas.

License

MIT Β© underworld14

Directories ΒΆ

Path Synopsis
cmd
pine command
Command pine is a git-native, local-first workspace for AI-assisted development: markdown tickets, a kanban web UI, attachments, search, and AI-context generation, all stored as files in a .pine/ directory.
Command pine is a git-native, local-first workspace for AI-assisted development: markdown tickets, a kanban web UI, attachments, search, and AI-context generation, all stored as files in a .pine/ directory.
internal
attach
Package attach ingests uploaded images and videos: it sniffs the real content type, optionally optimizes images (EXIF-orient, downscale, re-encode to lossy WebP, keep-smaller), and returns the bytes to persist plus metadata.
Package attach ingests uploaded images and videos: it sniffs the real content type, optionally optimizes images (EXIF-orient, downscale, re-encode to lossy WebP, keep-smaller), and returns the bytes to persist plus metadata.
cli
Package cli implements Pine's cobra command tree: init, serve, the Beads-style ticket commands (list/show/create/update/close/dep/ready), and the AI helpers (context/prompt/export/doctor/optimize).
Package cli implements Pine's cobra command tree: init, serve, the Beads-style ticket commands (list/show/create/update/close/dep/ready), and the AI helpers (context/prompt/export/doctor/optimize).
config
Package config loads, validates, and saves Pine's two JSON config files: .pine/config.json (project settings) and .pine/board.json (kanban columns).
Package config loads, validates, and saves Pine's two JSON config files: .pine/config.json (project settings) and .pine/board.json (kanban columns).
contextgen
Package contextgen builds the markdown that teaches an AI agent about the project: `pine context` (whole-project briefing) and `pine prompt <ID>` (a fix request for one ticket).
Package contextgen builds the markdown that teaches an AI agent about the project: `pine context` (whole-project briefing) and `pine prompt <ID>` (a fix request for one ticket).
doctor
Package doctor validates a .pine workspace: config/board schemas, ticket integrity, dependency/epic consistency, and attachment health.
Package doctor validates a .pine workspace: config/board schemas, ticket integrity, dependency/epic consistency, and attachment health.
gitx
Package gitx exposes read-only git awareness (branch, working-tree status, recent commits, tracked files) behind a small Client interface.
Package gitx exposes read-only git awareness (branch, working-tree status, recent commits, tracked files) behind a small Client interface.
search
Package search maintains an in-memory Bleve index over tickets.
Package search maintains an in-memory Bleve index over tickets.
server
Package server exposes the store over an HTTP+JSON API and serves the embedded web UI.
Package server exposes the store over an HTTP+JSON API and serves the embedded web UI.
store
Package store is Pine's single write path over a .pine/ directory.
Package store is Pine's single write path over a .pine/ directory.
ticket
Package ticket is the pure domain layer for Pine tickets: parsing and serializing the markdown+frontmatter file format, reading body sections, and computing the dependency/epic graph.
Package ticket is the pure domain layer for Pine tickets: parsing and serializing the markdown+frontmatter file format, reading body sections, and computing the dependency/epic graph.
view
Package view builds the presentation DTO for a ticket, joining the parsed ticket with computed dependency state, epic children, attachments, and its content hash.
Package view builds the presentation DTO for a ticket, joining the parsed ticket with computed dependency state, epic children, attachments, and its content hash.
watch
Package watch turns raw filesystem notifications under .pine/ into debounced, classified change events.
Package watch turns raw filesystem notifications under .pine/ into debounced, classified change events.
Package web provides the embedded SvelteKit build.
Package web provides the embedded SvelteKit build.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL