A structured initialization framework for collaborative human & AI coding projects
Project description
Bora
Bora — Brazilian Portuguese slang for let's go
Bora is a CLI that keeps your AI collaborator oriented across sessions, models, and projects.
Whether you're a developer building software with an AI coding agent, or a writer using AI to research and plan a manuscript, bora solves the same two problems:
- Context decay. Every new AI chat starts from zero. You re-explain the project, often inconsistently, and details get lost.
- Model drift. Switching between Claude, GPT, Gemini, or a local model means starting the briefing over.
Bora fixes this by maintaining a small, structured set of Markdown files inside your project. Any model — any tool — can read them to get oriented in seconds. The files travel with your project, stay in version control, and are always the authoritative source of what's happening and why.
Bora 0.3.0 ships two isolated profiles:
dev— for software projects: tickets, architecture decisions, task dashboards, and AI tool skill integration.write— for writing projects: chapter scaffolding, research interaction logs, story context, and summary generation.
Contents
- Installation
- Profiles
- For developers
- For writers
- Working across models
- Upgrading from 0.2.x
- Contributing
Installation
The recommended way to install Python CLIs globally is pipx, which gives bora its own isolated environment and puts it on your PATH without touching your system Python.
Install pipx (if you don't have it)
# macOS
brew install pipx
pipx ensurepath
# Linux / WSL
python3 -m pip install --user pipx
python3 -m pipx ensurepath
# Windows (PowerShell)
python -m pip install --user pipx
python -m pipx ensurepath
After running pipx ensurepath, open a new terminal so the updated PATH takes effect.
Install bora
# From PyPI (once published):
pipx install bora
# From GitHub:
pipx install git+https://github.com/tonyknight/Bora.git
Verify the install:
bora --version
Upgrade
pipx upgrade bora
Uninstall
pipx uninstall bora
Alternative: pip --user
If you prefer not to use pipx:
pip install --user bora
If bora isn't found after install, your user binary directory (~/.local/bin on Linux/macOS) may not be on your PATH. Add it:
# ~/.bashrc or ~/.zshrc
export PATH="$HOME/.local/bin:$PATH"
Development install (from source)
git clone https://github.com/tonyknight/Bora.git
cd Bora
pipx install -e .
Changes to the source take effect immediately — no reinstall needed.
Profiles
Every bora project has a profile stored in .bora/profile.json. The profile determines which commands are available and which appear in --help.
| Profile | Initialise with | Designed for |
|---|---|---|
dev |
bora dev init |
Software development |
write |
bora write init |
Writing projects |
Bora enforces profile isolation: running a dev command in a write project (or vice versa) exits with a clear error. This keeps the two workflows from interfering with each other.
If you run a command in a project that has no profile yet (for example, a project created before 0.3.0), bora prompts you to choose one and writes the file before continuing.
For developers
How it works (dev)
bora dev init scaffolds the project structure:
AGENTS.md ← AI agent instructions (entry point for any tool)
docs/ai/
Project.md ← what you're building and why (active project file)
Architecture.md ← design decisions, component layout, decision log
Tasks.md ← auto-generated dashboard (never hand-edit)
tickets/ ← one Markdown file per ticket
Projects/ ← archived project files (created on first bora dev project)
.bora/
profile.json ← profile lock (dev)
project.json ← active project file pointer and version
Each ticket is a Markdown file with YAML frontmatter for machine-readable state (status, priority, depends_on, subtasks) and a free-form body for human-readable context (description, acceptance criteria, notes). Tasks.md is regenerated from the tickets any time you run bora dev status.
When you finish a version and start a new one, bora dev project archives the current Project.md with full metadata and opens a fresh one — preserving the history of what was built, when, and what was shipped.
An AI agent reads AGENTS.md first, which tells it how to use the rest. It can then run bora dev ticket set, bora dev ticket note, and bora dev lint directly — the whole loop works from inside a model's shell.
Quick start (dev)
# Start in your project directory (existing or new)
cd /path/to/my-project
# Scaffold the project and install the bora skill for Claude Code
bora dev init claude
# Fill in what you're building
$EDITOR docs/ai/Project.md
# Create a ticket
bora dev ticket new "Implement login flow" --priority high
# Mark it in-progress (fuzzy ID match — no need to type the full ID)
bora dev ticket set 01 status in-progress
# Add a note as work progresses
bora dev ticket note 01 "Auth service wired up, still need session handling"
# Regenerate the task dashboard
bora dev status
# Brief a fresh model session (pipe to clipboard)
bora dev context | pbcopy
Dev commands
Project initialisation and versioning
| Command | What it does |
|---|---|
bora dev init [tool ...] |
Scaffold AGENTS.md, docs/ai/, tickets directory, .bora/profile.json, and .bora/project.json. Optionally install the bora skill for one or more AI tools: bora dev init claude, bora dev init all. Add --force to overwrite existing files. |
bora dev project [version] [description] |
Archive the current Project.md to docs/ai/Projects/ and create a new one. Prompts interactively for any missing arguments. See Project versioning for details. |
Tickets
| Command | What it does |
|---|---|
bora dev ticket new "<title>" |
Create a new ticket. Options: --type (feature/bug/chore/spike), --priority (high/medium/low), --parent <id> (for child tickets), --no-edit (skip opening $EDITOR). |
bora dev ticket list |
List all tickets in a table. Filters: --status, --type, --priority, --blocked. |
bora dev ticket show <id> |
Print a ticket's full contents. Fuzzy ID match: 01 matches 20260628-01-my-ticket. |
bora dev ticket set <id> <field> <value> |
Update a frontmatter field. Settable fields: title, type, priority, status, notes, parent. Setting status done auto-populates the closed date. |
bora dev ticket note <id> "<text>" |
Append a dated entry to a ticket's Notes section. Use this to record progress without rewriting the whole file. |
bora dev ticket subtask <id> <subtask-id> <status> |
Update a frontmatter subtask's status (todo/in-progress/done). |
Project state
| Command | What it does |
|---|---|
bora dev status |
Regenerate docs/ai/Tasks.md from the current ticket state. |
bora dev context [--budget N] |
Print briefing content for a fresh model session — all the files an agent should read, in order. Pass --budget <tokens> to get a token-bounded version. |
bora dev lint |
Validate frontmatter and cross-references across all tickets. Run this after any model writes to a ticket file. |
Architecture decisions
| Command | What it does |
|---|---|
bora dev decision new "<title>" |
Append a dated, templated decision entry to Architecture.md and open it in $EDITOR. |
AI tool skills
| Command | What it does |
|---|---|
bora dev skill install <tool> |
Install the bora skill for an AI tool. Tools: claude, opencode, all. Default: user-level install (~/.claude/). Add --project to install inside the repo instead. |
bora dev skill uninstall <tool> |
Remove the bora skill. |
bora dev skill list |
Show where the bora skill is installed for each known tool. |
AI tool skills
Claude Code, OpenCode, and other agentic tools support skills — directories containing a SKILL.md that the agent loads when its description matches the current task. Bora ships a skill that tells the agent how to use the CLI and maintain the docs/ai/ files correctly.
Install as part of bora dev init:
bora dev init claude # scaffold + skill for Claude Code
bora dev init claude opencode # scaffold + both tools
bora dev init all # scaffold + all known tools
Or install the skill on its own (after bora dev init):
# User-level — available in every project
bora dev skill install claude
bora dev skill install all
# Project-level — ships inside this repo
bora dev skill install claude --project
Show what's installed where:
bora dev skill list
Remove:
bora dev skill uninstall claude # user-level
bora dev skill uninstall claude --project # this repo only
The uninstall command only removes a SKILL.md whose frontmatter identifies it as bora's — it won't delete a skill it didn't create. Pass --force to override.
| Tool | User-level path | Project-level path |
|---|---|---|
claude |
~/.claude/skills/bora/SKILL.md |
./.claude/skills/bora/SKILL.md |
opencode |
~/.config/opencode/skills/bora/SKILL.md |
./.opencode/skills/bora/SKILL.md |
Project versioning
When a version ships and you're ready to start the next one, run:
bora dev project v0.4.0 "Describe what this version is for"
Or omit the arguments and bora prompts you:
bora dev project
# Project version: v0.4.0
# Project description (280 chars max): Describe what this version is for
What happens:
-
Archive — the current
Project.mdis moved todocs/ai/Projects/with a(YYYY-MM-DD)date prefix added to the filename (if it doesn't already have one). The file gets archival frontmatter injected:status: archivedarchived_dateandarchived_at_versioncompleted_tickets— list of all tickets closed during this versiongit_log— commits since the project'sstart_date(or last 50 if no start date)
-
Create — a new
(YYYY-MM-DD) Project.mdis created atdocs/ai/with frontmatter pre-populated:version,description,status: openstart_dateandlast_reviewedset to today
-
Update pointer —
.bora/project.jsonis updated so all tools (context briefing, task dashboard) automatically pick up the new file.
The (YYYY-MM-DD) date prefix format is used consistently across bora for all date-stamped files — project archives, Summary archives, and any other auto-named files.
Dev conventions
- Ticket IDs are generated, not chosen. The format is
YYYYMMDD-NN-slug. Never rename ticket files — the ID is the source of truth fordepends_onandparentreferences. Tasks.mdis auto-generated. Never hand-edit it. Update tickets and runbora dev status.- Subtasks live in two places by design. Major subtasks appear in frontmatter (
subtasks:list) — they're queryable and visible inTasks.md. Small subtasks are Markdown checkboxes in the ticket body — they're counted but not individually tracked. - Decisions are append-only. Add new entries to
Architecture.md; don't rewrite old ones. History matters. AGENTS.mdis the entry point. AI tools that supportAGENTS.md(Claude Code, Cursor, others) load it automatically. It tells the agent what the project is, how to work, and what commands to use.
For writers
How it works (write)
bora write init scaffolds a writing project:
AGENTS.md ← AI agent instructions (role, boundaries, workflow rules)
doc/ai/
Project.md ← story overview: premise, plot, characters, worldbuilding
Summary.md ← latest AI-generated context briefing (ephemeral)
Summary/ ← archive of previous summaries
.bora/
profile.json ← profile lock (write)
As you create chapters, bora adds:
Chapters/
Chapter 001 - The Arrival/
001 - The Arrival.md ← manuscript (author-only, agents never write here)
001 - ChapterProject.md ← planning: beats, arcs, pacing, agent notes
001 - Research.md ← research log: AI interactions, sources, verification
The core workflow is:
- Write your chapter notes and research questions in
ChapterProject.md. - Ask your AI to research topics. The agent logs interactions in
Research.md. - Run
bora write statusto compile everything into a structured briefing. - Paste the briefing into a new chat with your AI. Ask it to generate an updated
Summary.md. - Save the response as
Summary.md. Next time you runbora write status, it's archived and a fresh one is generated.
The AI never touches your manuscript. The creative work stays yours.
Quick start (write)
# Create and enter your project directory
mkdir my-novel && cd my-novel
# Scaffold the write project
bora write init
# Set up your story context
$EDITOR AGENTS.md # tell your AI its role and boundaries for this story
$EDITOR doc/ai/Project.md # add your premise, characters, plot structure
# Create your first chapter
bora write chapter "The Arrival"
# Fill in the chapter plan
$EDITOR "Chapters/Chapter 001 - The Arrival/001 - The Arrival ChapterProject.md"
# Add a second chapter
bora write chapter "The Conflict"
# Compile a briefing for your AI model
bora write status
# Paste the output into Claude / ChatGPT / your model of choice
# Ask: "Based on this project context, generate an updated Summary.md"
# Save the response as Summary.md
Write commands
Project initialisation
| Command | What it does |
|---|---|
bora write init |
Scaffold AGENTS.md, doc/ai/Project.md, Summary.md, Summary/, and .bora/profile.json. Does not create chapter directories (use bora write chapter for that). Add --force to overwrite existing files. |
Chapters
| Command | What it does |
|---|---|
bora write chapter "<name>" |
Create the next chapter directory under Chapters/. The ID is 3-digit zero-padded and auto-increments by scanning existing chapter directories (001, 002, ...). Creates three files: an empty manuscript, a ChapterProject.md planning template, and a Research.md log. |
Project status
| Command | What it does |
|---|---|
bora write status |
Read Project.md, all ChapterProject.md files, and all Research.md files. Compute approximate word counts, chapter status counts, and research topic frequency. Archive the existing Summary.md to Summary/YYYY-MM-DD - Summary.md (collision-safe). Print a structured briefing to stdout. |
Skills
| Command | What it does |
|---|---|
bora write skill install obsidian |
Install a vault-aware agent prompt to .obsidian/plugins/bora-writer/ (SKILL.md, manifest.json, README.md). Add --force to overwrite. |
bora write skill uninstall obsidian |
Remove the .obsidian/plugins/bora-writer/ directory. Add --force if SKILL.md is missing. |
Obsidian integration
If you use Obsidian as your writing environment, bora can install a vault-aware prompt that orients your AI to the project's structure:
bora write skill install obsidian
This creates .obsidian/plugins/bora-writer/ with:
SKILL.md— a prompt template describing the vault structure, the chapter layout, theResearch.mdformat, and the rule that agents never write to manuscript files. Paste its contents into your AI model's system prompt or context window.manifest.json— Obsidian community plugin metadata.README.md— setup instructions.
To remove it:
bora write skill uninstall obsidian
Write conventions
- Agents never write to manuscript files. The
001 - Chapter Name.mdfiles are author-only. If an agent modifies one, treat that as a mistake — theAGENTS.mdtemplate instructs it not to. Research.mdis a mixed Markdown/YAML log. Each topic section has a small YAML block (topic,date,agent,word_count,verified) followed by the free-form interaction. The YAML lets you track what's been verified and by whom.Summary.mdis ephemeral. Everybora write statusrun archives it. Don't invest in maintaining it by hand — that's the AI's job.ChapterProject.mddrives the briefing. Thestatusfield (draft,in-progress,completed) andtarget_wordsfeed the compiled status output. Keep them up to date.- Chapter IDs are calculated, not counted. Deleting a chapter directory doesn't reset the counter — the next chapter always gets
max(existing IDs) + 1. You won't accidentally reuse an ID.
Working across models
Bora is model-agnostic. It produces plain Markdown and YAML that any LLM can read.
Chat-only models (web Claude, ChatGPT, Gemini, etc.)
For dev projects, run bora dev context --budget <N> and paste the output as your first message. The model gets the same complete briefing every time.
For write projects, run bora write status and paste the output. Ask the model to generate a Summary.md and save its response.
Agentic tools with file access (Claude Code, Cursor, Aider, etc.)
The model reads AGENTS.md and follows its instructions to discover the rest. For dev projects, the agent can run bora dev ticket set, bora dev lint, and bora dev status directly from its shell as work progresses.
Local models
The same flows work with local models. Smaller models (under ~14B parameters) may occasionally produce malformed YAML frontmatter in ticket or planning files. Run bora dev lint after any model writes to a ticket file to catch these early.
Upgrading
From 0.3.x to 0.3.5
0.3.5 adds .bora/project.json to track the active project file. New projects get it automatically via bora dev init. For existing 0.3.x projects, bora falls back to docs/ai/Project.md without a pointer file — everything keeps working. The pointer is written the first time you run bora dev project.
Summary archives are now named (YYYY-MM-DD) Summary.md instead of YYYY-MM-DD - Summary.md. Existing archives are not renamed.
From 0.2.x to 0.3.x
Bora 0.3.0 moved all commands under bora dev or bora write. The old top-level bora init prints a deprecation warning and exits.
-
Upgrade bora:
pipx upgrade bora
-
Add a profile file. Run any
bora devcommand and choosedevat the prompt — bora writes the file automatically. Or create it manually:mkdir -p .bora cat > .bora/profile.json << 'EOF' { "version": "0.3.5", "profile": "dev", "initialized_at": "2026-01-01T00:00:00+00:00", "config": { "auto_archive": true, "research_log_mode": "full_interaction" } } EOF
-
All existing tickets,
docs/ai/files, andAGENTS.mdare untouched. Commands that used to bebora ticket ...are nowbora dev ticket ....
Contributing
The source is in bora/. Here's what each module does:
| File | Purpose |
|---|---|
cli.py |
Click command surface — dev and write subgroups, profile-aware help filtering |
profile.py |
.bora/profile.json read/write/lock, upgrade prompt |
paths.py |
Repo-root detection and shared path constants |
templates.py |
All scaffolded file templates (dev and write) |
ticket.py |
Frontmatter parsing, fuzzy ID matching, body progress tracking |
create.py |
Chronological ticket ID generation |
lint.py |
Frontmatter validation rules |
status.py |
Tasks.md generation |
context.py |
Briefing assembly with optional token budget |
skill.py |
Dev SKILL.md template and per-tool install/uninstall |
dev_project.py |
bora dev project — archive, create, and project.json management |
writer_init.py |
bora write init scaffolding |
writer_chapter.py |
bora write chapter scaffolding and ID calculation |
writer_status.py |
bora write status context compiler and Summary archival |
writer_skill.py |
bora write skill install/uninstall obsidian |
Tests live in tests/, one file per phase. Run them with:
python -m pytest tests/ -v
To manually smoke-test a dev project:
mkdir /tmp/test-bora && cd /tmp/test-bora && git init
bora dev init
bora dev ticket new "Test ticket" --priority high --no-edit
bora dev ticket set 01 status in-progress
bora dev status
bora dev lint
To smoke-test a write project:
mkdir /tmp/test-write && cd /tmp/test-write
bora write init
bora write chapter "First Chapter"
bora write chapter "Second Chapter"
bora write status
License
MIT.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file bora-0.3.5.tar.gz.
File metadata
- Download URL: bora-0.3.5.tar.gz
- Upload date:
- Size: 52.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4d272f541358eb58fe968239d2243b61619e7cc0981ba649dc5747324635615c
|
|
| MD5 |
469cb80827f6e7717d0ae95d8982ca93
|
|
| BLAKE2b-256 |
4fdcdcd5389a3d775b5dbaccfce6444a3411ef8e35cf990a6b367d2a7f7854de
|
Provenance
The following attestation bundles were made for bora-0.3.5.tar.gz:
Publisher:
publish.yml on tonyknight/Bora
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bora-0.3.5.tar.gz -
Subject digest:
4d272f541358eb58fe968239d2243b61619e7cc0981ba649dc5747324635615c - Sigstore transparency entry: 2044500351
- Sigstore integration time:
-
Permalink:
tonyknight/Bora@bdc2e068e93737b70cd8074989ef399cc6b721f5 -
Branch / Tag:
refs/tags/v0.3.6 - Owner: https://github.com/tonyknight
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@bdc2e068e93737b70cd8074989ef399cc6b721f5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file bora-0.3.5-py3-none-any.whl.
File metadata
- Download URL: bora-0.3.5-py3-none-any.whl
- Upload date:
- Size: 47.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2902124435a0cd1badddd9f3a3ed6fc66088715d2dcf5eb3158f1f61da797169
|
|
| MD5 |
177f7f89b84f8bc1148113f7e1d966d3
|
|
| BLAKE2b-256 |
da31c335ec75c4d7a409599600bac1b93617f5433aa04f3e92fcfc3bdcc836f1
|
Provenance
The following attestation bundles were made for bora-0.3.5-py3-none-any.whl:
Publisher:
publish.yml on tonyknight/Bora
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bora-0.3.5-py3-none-any.whl -
Subject digest:
2902124435a0cd1badddd9f3a3ed6fc66088715d2dcf5eb3158f1f61da797169 - Sigstore transparency entry: 2044500379
- Sigstore integration time:
-
Permalink:
tonyknight/Bora@bdc2e068e93737b70cd8074989ef399cc6b721f5 -
Branch / Tag:
refs/tags/v0.3.6 - Owner: https://github.com/tonyknight
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@bdc2e068e93737b70cd8074989ef399cc6b721f5 -
Trigger Event:
push
-
Statement type: