Metadata-Version: 2.4
Name: tana
Version: 0.1.0
Summary: A package manager for Git-based knowledge packages
Author: Tana
License: MIT
Keywords: cli,git,knowledge,package-manager
Requires-Python: >=3.10
Requires-Dist: rich>=13.0.0
Requires-Dist: tomli-w>=1.0.0
Requires-Dist: tomli>=1.1.0; python_version < '3.11'
Requires-Dist: typer>=0.12.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Description-Content-Type: text/markdown

# Tana

**Tana is a package manager for Git-based knowledge vaults.**

A knowledge vault is simply a folder — usually a Git repository — of knowledge.
Tana manages the adding, listing, and updating of these vaults on your machine.
It is **not** a Git replacement, and it is **not** an AI tool — it is a small,
focused manager that happens to use Git as its transport.

---

## Installation

Requires Python 3.10+.

### With pipx (recommended)

[pipx](https://pipx.pypa.io) installs the `tana` command into its own isolated
environment and puts it on your `PATH` — no venv juggling.

```bash
# Install straight from GitHub
pipx install git+https://github.com/wxharry/tana.git

# …or from a local clone
git clone https://github.com/wxharry/tana.git
cd tana
pipx install .
```

Upgrade or remove later with:

```bash
pipx upgrade tana
pipx uninstall tana
```

### With pip (editable / development)

```bash
git clone https://github.com/wxharry/tana.git
cd tana
pip install -e .          # or: pip install -e ".[dev]"  (tests included)
```

Any of these expose the `tana` command.

---

## Quick start

```bash
# Set up Tana in ~/.tana
tana init

# Add a knowledge vault — source type is detected automatically
tana add git@github.com:company/git-knowledge-vault.git --name my-vault   # Git URL → cloned
tana add https://github.com/company/php.git --name php
tana add ~/Documents/wiki --name wiki                                # folder  → linked in place

# See what's tracked
tana list

# Update everything (or a single vault)
tana update
tana update my-vault

# Remove a vault (asks before deleting files)
tana remove my-vault
tana remove my-vault --keep-files

# Discover the agent skills a vault carries
tana skills
tana skills show my-vault rebase
tana skills export
tana skills export --target claude
```

---

## CLI reference

| Command | Description |
| --- | --- |
| `tana init` | Create `~/.tana/`, `~/.tana/vaults/`, and `~/.tana/config.toml`. |
| `tana add <source> [--name NAME]` | Add a vault. `<source>` is a Git URL (cloned) or a local folder path (linked in place). Name inferred unless overridden. |
| `tana list` | Show tracked vaults as a table. |
| `tana info <name>` | Show a vault's URL, path, branch, commit, last change, and dirty state. |
| `tana update [name]` | Update all vaults, or a single named vault. |
| `tana remove <name> [--keep-files]` | Remove a vault. Asks before deleting files unless `--keep-files`. |
| `tana skills` | List every agent skill discovered across tracked vaults. |
| `tana skills show <vault> <skill>` | Print a skill's Markdown with placeholders rendered. |
| `tana skills export [--target claude]` | Export skills to `~/.tana/exports/`. `--target claude` uses a Claude-specific folder. |

### Vault kinds

`tana add` detects the source type:

| Kind | Source | Lives in | Updates | Remove |
| --- | --- | --- | --- | --- |
| `git` | a Git URL (`git@…`, `https://…`) | `~/.tana/vaults/<name>` (cloned) | fetch + fast-forward | asks before deleting files |
| `local` | a local folder path | wherever it already is (not copied) | pulls if the folder is a Git repo, otherwise skipped | only unlinks — **never deletes your files** |

The `local` kind is for a knowledge base you maintain yourself — e.g. an
Obsidian vault:

```bash
tana add ~/Documents/wiki --name wiki
```

Tana tracks it in place. There is no second copy to drift out of sync, and
removing only forgets it.

### How updates stay safe

For each vault, `tana update`:

1. Verifies the vault directory exists and is a Git repository.
2. Detects local modifications (`git status --porcelain`).
3. **Skips** any vault with local changes — you commit or stash manually.
4. Otherwise fetches and fast-forwards only.

Tana never commits, pushes, stashes, merges, or resolves conflicts. If a
fast-forward is not possible, the update is reported as **Failed** and left for
you to handle with Git directly.

Per-vault status is one of: **Updated**, **Already up to date**, **Skipped**,
or **Failed**.

---

## Agent skills

A vault can carry **skills**: Markdown files that tell an AI agent *when* to use
the vault, *what* knowledge it holds, *where* to look, and *which* conventions to
follow. Tana discovers, lists, renders, and exports these files. It does **not**
own or interpret the knowledge — skills are content the vault carries, and agent
integrations consume the exported result.

### The `skills/` convention

A vault exposes skills under its own `skills/` directory — an ordinary content
folder the vault already owns, alongside `notes/` and `examples/`. Tana imposes
no special metadata directory. Every `*.md` under `skills/` is one skill; its
filename (without `.md`) is the skill name. Non-Markdown files are ignored.

```text
git-knowledge-vault/
├── skills/          # agent-readable skills (Tana discovers these)
│   ├── rebase.md
│   └── merge.md
├── notes/           # the knowledge itself
├── examples/
└── README.md
```

### Example skill — `skills/rebase.md`

```markdown
# Git Rebase Skill

Use this skill when the user asks about:
- git rebase / `git rebase --onto`
- interactive rebase (`git rebase -i`) — squash, fixup, reword, drop
- replaying commits onto a new base
- resolving conflicts during a rebase (`--continue` / `--abort` / `--skip`)

Knowledge vault: {{vault_name}}
Knowledge vault path: {{vault_path}}
Skill file: {{skill_path}}

Before answering:
1. Search this vault's notes and examples for the branching model.
2. Prefer the team convention: rebase local branches, never shared history.
3. Explain tradeoffs vs. merge clearly.
```

### Placeholders

Tana substitutes these tokens when showing or exporting a skill (plain string
replacement, for now):

| Placeholder | Replaced with |
| --- | --- |
| `{{vault_name}}` | the vault name |
| `{{vault_path}}` | absolute path to the vault on disk |
| `{{skill_name}}` | the skill name (filename without `.md`) |
| `{{skill_path}}` | absolute path to the skill file |

### Listing

```bash
$ tana skills
VAULT       SKILL    FILE
my-vault    merge    ~/.tana/vaults/my-vault/skills/merge.md
my-vault    rebase   ~/.tana/vaults/my-vault/skills/rebase.md
```

### Exporting

`tana skills export` writes each skill to `~/.tana/exports/skills/` as
`<vault>-<skill>.md`, with placeholders rendered:

```text
~/.tana/exports/skills/my-vault-rebase.md
~/.tana/exports/skills/my-vault-merge.md
```

`--target claude` is a simple folder export — it writes to
`~/.tana/exports/claude/skills/` instead. Tana does **not** touch Claude's real
config directory; the exported files are yours to copy wherever you like.

---

## Claude Code plugin

Tana ships as a **Claude Code plugin** (the repo root doubles as the plugin
root: `.claude-plugin/`, `skills/`, `hooks/`, `statusline.sh`). The plugin does
two things:

1. **Wraps the CLI as skills** — each `tana` command is a skill Claude can run
   for you by name or in plain language (`/tana-add ~/Documents/wiki`, "list my
   tana vaults", "update the wiki vault").
2. **Thinks with your vaults** — a toggle that puts a fixed `[TANA]` badge on the
   statusline and injects a directive telling Claude to consult your tracked
   vaults (and the `skills/` they carry) *before* answering.

Unlike a standalone thinking plugin, tana needs no separate "bind" step — the
vault list comes straight from `~/.tana/config.toml`, so `tana add` / `tana
remove` **are** the binding. (The `tana skills` command is intentionally *not*
exposed as a plugin skill — the plugin itself is the skills surface.)

### Install

This repository is also a Claude marketplace (`.claude-plugin/marketplace.json`).
Register it, then install the plugin:

```
/plugin marketplace add local-dev https://github.com/wxharry/tana
/plugin marketplace update local-dev
/plugin install tana@local-dev
```

Then reload Claude Code so the hooks and skills register.

### Skills

| Skill | Runs / does |
| --- | --- |
| `/tana-init` | `tana init` |
| `/tana-add <source> [name]` | `tana add` (Git URL cloned, local folder linked) |
| `/tana-list` | `tana list` |
| `/tana-info <name>` | `tana info` |
| `/tana-update [name]` | `tana update` |
| `/tana-remove <name> [--keep-files]` | `tana remove` |
| `/tana on` \| `/tana off` | enable / disable the `[TANA]` badge + "think with your vaults" directive |

### The `[TANA]` badge and thinking directive

`/tana on` writes `~/.tana-active=on`, validates that at least one tracked vault
resolves to a real directory, and patches your statusline to prepend a cyan
`[TANA]` badge. Two hooks then feed Claude a directive built from the live vault
list:

* **SessionStart** — foundational priming at session boot.
* **UserPromptSubmit** — a per-turn reminder.

The directive tells Claude to read the relevant vault's `skills/*.md` to route,
grep the vault, open the top matches, and cite findings as
`(from <vault>: <title>)`. Because the list is read live from tana's config,
adding or removing a vault changes the substrate immediately — no re-toggle.

`/tana off` clears the flag and removes the badge block from your statusline.
Both patch operations are idempotent and guarded by
`# >>> tana-plugin-badge >>>` markers, so they never clobber the rest of your
statusline script.

---

## Configuration

Everything lives under `~/.tana`:

```text
~/.tana/
├── config.toml      # tracked vaults
└── vaults/          # cloned Git vaults
```

`config.toml` looks like:

```toml
[vaults.my-vault]
url = "git@github.com:company/git-knowledge-vault.git"
path = "/Users/me/.tana/vaults/my-vault"
```

---

## Project layout

```text
tana/
├── pyproject.toml
├── README.md
├── src/
│   └── tana/
│       ├── __init__.py
│       ├── cli.py        # Typer commands + Rich output (presentation only)
│       ├── config.py     # read/write ~/.tana/config.toml (testable)
│       ├── git.py        # the only module that shells out to Git
│       ├── models.py     # Vault dataclass + name inference
│       ├── skills.py     # discover + render a vault's skills/*.md
│       └── export.py     # write skills into agent-friendly folders
├── examples/
│   └── git-knowledge-vault/   # sample vault with a skills/ directory
└── tests/
```

---

## Design philosophy

**Tana is not a Git wrapper.** Git keeps everything it is good at, and Tana
stays out of its way.

| Git owns | Tana owns |
| --- | --- |
| commits, branches, history | adding vaults |
| remotes, conflict resolution | local organization |
| | vault management & updates |

Two principles fall out of this split:

- **User-facing language is vault language** — *add*, *update*, *vault* — not
  *clone* or *pull*.
- **Layers are separated** — Git operations (`git.py`) are isolated from config
  (`config.py`), skills (`skills.py`/`export.py`), and CLI presentation
  (`cli.py`), which keeps each piece small and testable.

Tana never reaches into a vault's knowledge — it only reads the `skills/` a
vault chooses to publish. A vault stays a plain folder of Markdown that works
fine without Tana.

---

## Tests

```bash
pip install -e ".[dev]"
pytest
```

Coverage includes vault name inference, config read/write round-trips, duplicate
vault detection, update-skipping when local changes exist, and skill discovery /
placeholder rendering / export.

---

## Roadmap

Skill discovery and export (above) are the first step of AI-agent integration.
The intended future — documented but **not yet implemented**:

- **First-class agent integrations** — beyond the generic folder export, native
  targets for **Claude**, **Cursor**, and **Codex** that drop skills where each
  tool expects them.
- **MCP server** — expose tracked vaults and their skills to agents over the
  Model Context Protocol instead of (or alongside) file export.
- **Registry support** — add a vault by name instead of a raw Git URL, with
  public/private registries and vault search.
- **Vault manifests** — declared metadata per vault (description, version, tags,
  and which skills it provides).
- **Skill dependencies** — let a skill declare other skills or vaults it builds
  on, so agents can pull in the full context a skill needs.

The architecture intentionally keeps Git (`git.py`), config (`config.py`),
skills (`skills.py`/`export.py`), and CLI presentation (`cli.py`) separate so
these can be layered in without rewrites. No AI vendor is hardcoded as the core
model — `claude` is just one export target among future others.
