docs: simplify README and extract full reference to USAGE.md
- Condensed README to quick overview (~40 lines) with key features - Added install instructions for Alpine, Arch, source, and Docker - Created USAGE.md with full command reference, server mode, OIDC, and permission model docs - New features documented: server mode, OIDC authentication, per-node permissions, multiplatform auto-builds Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
280
README.md
280
README.md
@@ -1,266 +1,52 @@
|
|||||||
# Axolotl
|
# Axolotl
|
||||||
|
|
||||||
CLI-native lightweight issue tracker for you and your agents. A SQLite-based
|
CLI-native issue tracker for you and your agents. Single binary, SQLite-backed, ~1300 lines of Go.
|
||||||
single portable binary, built from ~1300 lines of Go code.
|
|
||||||
|
|
||||||
## Features
|
## Install
|
||||||
|
|
||||||
- **Issues with dependencies** - blocks, subtask, related relations
|
**Alpine Linux** (apk):
|
||||||
- **Tagging system** - flexible tags with `_key::value` property pattern
|
Download from the Gitea package registry. Have a look
|
||||||
- **Namespacing** - organize issues by project or team
|
[here](https://g.eliaskohout.de/eliaskohout/-/packages/alpine/axolotl/).
|
||||||
- **Due dates** - track deadlines
|
|
||||||
- **Thread-safe** - WAL mode for concurrent access
|
|
||||||
- **Multiuser support** - @mentions and assignments, inbox per user
|
|
||||||
- **JSON output** - all commands support `--json` for agent integration
|
|
||||||
- **Alias system** - define custom command shortcuts with argument expansion
|
|
||||||
- **Single binary** - no dependencies, portable `.ax.db` file
|
|
||||||
|
|
||||||
## Installation
|
**Arch Linux** (pacman):
|
||||||
|
Download from the Gitea package registry. Have a look
|
||||||
|
[here](https://g.eliaskohout.de/eliaskohout/-/packages/arch/axolotl/).
|
||||||
|
|
||||||
|
**From source:**
|
||||||
```bash
|
```bash
|
||||||
go build -o ax .
|
go build -o ax ./src
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Docker (server mode):**
|
||||||
|
```bash
|
||||||
|
docker run -v ./data:/data g.eliaskohout.de/eliaskohout/axolotl-server:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
Packages are built automatically on every version tag for `linux/amd64` and `linux/arm64`.
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Initialize a new database
|
ax init . # create .ax.db in current dir
|
||||||
ax init .
|
ax add "Fix login bug" --prio high # create an issue
|
||||||
|
ax list --status open # list open issues
|
||||||
# Create an issue
|
ax show abc12 # show issue details
|
||||||
ax add "Implement feature X" --tag backend --prio high
|
ax update abc12 --status done # close issue
|
||||||
|
ax inbox # your @mention inbox
|
||||||
# Create with relations
|
|
||||||
ax add "Fix bug in auth" --rel blocks:abc12
|
|
||||||
|
|
||||||
# List open issues
|
|
||||||
ax list --status open
|
|
||||||
|
|
||||||
# Show issue details
|
|
||||||
ax show abc12
|
|
||||||
|
|
||||||
# Update an issue
|
|
||||||
ax update abc12 --status done
|
|
||||||
|
|
||||||
# View your inbox
|
|
||||||
ax inbox
|
|
||||||
|
|
||||||
# Define an alias
|
|
||||||
ax alias mywork "list --namespace myproject --status open" --desc "My project tasks"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Commands
|
## Key Features
|
||||||
|
|
||||||
### `ax init [path]`
|
- **Graph relations** — `blocks`, `subtask`, `related`, `assignee`
|
||||||
|
- **Namespaces** — organize issues by project or team
|
||||||
|
- **Permissions** — per-node access control (`can_read`, `can_write`, `has_ownership`)
|
||||||
|
- **Aliases** — custom shortcuts with `$me`, `$1`, `$@` expansion
|
||||||
|
- **JSON output** — `--json` flag on all commands for agent integration
|
||||||
|
- **Multiuser** — `@mention` auto-creates inbox entries; `AX_USER` to switch users
|
||||||
|
- **Server mode** — HTTP JSON API with optional OIDC authentication (`ax serve` / `ax login`)
|
||||||
|
- **Portable** — single `.ax.db` file, no server required
|
||||||
|
|
||||||
Create a new `.ax.db` database in the specified directory (default: current).
|
For full command reference and examples, see [USAGE.md](USAGE.md).
|
||||||
|
|
||||||
### `ax add <title> [flags]`
|
|
||||||
|
|
||||||
Create a new node.
|
|
||||||
|
|
||||||
| Flag | Description |
|
|
||||||
|------|-------------|
|
|
||||||
| `--type` | Node type: `issue` (default), `note`, `user`, `namespace` |
|
|
||||||
| `--status` | Status: `open` (default), `done` |
|
|
||||||
| `--prio` | Priority: `high`, `medium`, `low` |
|
|
||||||
| `--namespace` | Namespace (default: current user) |
|
|
||||||
| `--tag` | Add tag (repeatable) |
|
|
||||||
| `--due` | Due date |
|
|
||||||
| `--content` | Content/body text |
|
|
||||||
| `--rel` | Add relation `type:id` (repeatable) |
|
|
||||||
|
|
||||||
### `ax update <id> [flags]`
|
|
||||||
|
|
||||||
Update a node.
|
|
||||||
|
|
||||||
| Flag | Description |
|
|
||||||
|------|-------------|
|
|
||||||
| `--title` | New title |
|
|
||||||
| `--status` | New status |
|
|
||||||
| `--prio` | New priority |
|
|
||||||
| `--type` | New type |
|
|
||||||
| `--namespace` | New namespace |
|
|
||||||
| `--assignee` | New assignee |
|
|
||||||
| `--due` | New due date |
|
|
||||||
| `--clear-due` | Clear due date |
|
|
||||||
| `--content` | New content |
|
|
||||||
| `--tag` | Add tag (repeatable) |
|
|
||||||
| `--tag-remove` | Remove tag (repeatable) |
|
|
||||||
| `--rel` | Add relation `type:id` (repeatable) |
|
|
||||||
| `--rel-remove` | Remove relation `type:id` (repeatable) |
|
|
||||||
|
|
||||||
### `ax show <id>`
|
|
||||||
|
|
||||||
Display node details.
|
|
||||||
|
|
||||||
### `ax list [flags]`
|
|
||||||
|
|
||||||
Query and list nodes.
|
|
||||||
|
|
||||||
| Flag | Description |
|
|
||||||
|------|-------------|
|
|
||||||
| `--type` | Filter by type |
|
|
||||||
| `--status` | Filter by status |
|
|
||||||
| `--prio` | Filter by priority |
|
|
||||||
| `--namespace` | Filter by namespace |
|
|
||||||
| `--tag` | Filter by tag (repeatable) |
|
|
||||||
| `--assignee` | Filter by assignee |
|
|
||||||
| `--mention` | Filter by mention |
|
|
||||||
|
|
||||||
### `ax edit <id>`
|
|
||||||
|
|
||||||
Open node content in `$EDITOR`.
|
|
||||||
|
|
||||||
### `ax del <id> [-f|--force]`
|
|
||||||
|
|
||||||
Delete a node. Prompts for confirmation unless `--force`.
|
|
||||||
|
|
||||||
### `ax alias [name] [command] [flags]`
|
|
||||||
|
|
||||||
Manage aliases.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ax alias # list all aliases
|
|
||||||
ax alias mywork "list --tag work" # create alias
|
|
||||||
ax alias mywork # show alias command
|
|
||||||
ax alias mywork "list --tag work2" # update alias
|
|
||||||
ax alias del mywork # delete alias
|
|
||||||
```
|
|
||||||
|
|
||||||
**Default aliases:**
|
|
||||||
|
|
||||||
| Alias | Command | Description |
|
|
||||||
|-------|---------|-------------|
|
|
||||||
| `mine` | `list --assignee $me --type issue --status open` | Show open issues assigned to you |
|
|
||||||
| `due` | `list --type issue --status open` | Show open issues |
|
|
||||||
| `inbox` | `list --mention $me` | Show your inbox |
|
|
||||||
|
|
||||||
**Alias argument expansion:**
|
|
||||||
|
|
||||||
| Variable | Expands to |
|
|
||||||
|----------|------------|
|
|
||||||
| `$me` | Current username |
|
|
||||||
| `$@` | All arguments |
|
|
||||||
| `$1`, `$2`, ... | Positional arguments |
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Create alias with argument expansion
|
|
||||||
ax alias find "list --tag $1 --status $2"
|
|
||||||
ax find backend open # expands to: list --tag backend --status open
|
|
||||||
```
|
|
||||||
|
|
||||||
## Relations
|
|
||||||
|
|
||||||
Relations connect nodes together:
|
|
||||||
|
|
||||||
| Type | Meaning | Behavior |
|
|
||||||
|------|---------|----------|
|
|
||||||
| `blocks` | A blocks B — B can't close until A is done | Enforced on status=done |
|
|
||||||
| `subtask` | A is a subtask of B | |
|
|
||||||
| `related` | A is related to B | |
|
|
||||||
| `assignee` | A is assigned to user | Single-value; set via `--assignee` flag |
|
|
||||||
| `in_namespace` | A belongs to namespace | Single-value; set via `--namespace` flag |
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Block an issue (B can't close until A is done)
|
|
||||||
ax update A --rel blocks:B
|
|
||||||
|
|
||||||
# Assign to user
|
|
||||||
ax update abc12 --assignee alice
|
|
||||||
|
|
||||||
# Create subtask
|
|
||||||
ax update abc12 --rel subtask:parent12
|
|
||||||
```
|
|
||||||
|
|
||||||
## Tags and Properties
|
|
||||||
|
|
||||||
Tags are flexible labels. Tags with pattern `_key::value` are properties:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Regular tag
|
|
||||||
ax add "Task" --tag backend
|
|
||||||
|
|
||||||
# Property tags (set via flags)
|
|
||||||
ax add "Task" --type issue --status open --prio high
|
|
||||||
# Equivalent to: --tag _type::issue --tag _status::open --tag _prio::high
|
|
||||||
```
|
|
||||||
|
|
||||||
**Built-in properties:**
|
|
||||||
|
|
||||||
| Property | Values | Required |
|
|
||||||
|----------|--------|----------|
|
|
||||||
| `_type` | `issue`, `note`, `user`, `namespace` | Yes (default: `issue`) |
|
|
||||||
| `_status` | `open`, `done` | No |
|
|
||||||
| `_prio` | `high`, `medium`, `low` | No |
|
|
||||||
|
|
||||||
## Mentions and Inbox
|
|
||||||
|
|
||||||
Use `@username` in title or content to automatically add to user's inbox:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ax add "Review PR @alice" --content "@bob please check"
|
|
||||||
# Both alice and bob get this in their inbox
|
|
||||||
```
|
|
||||||
|
|
||||||
View inbox:
|
|
||||||
```bash
|
|
||||||
ax inbox # your inbox
|
|
||||||
AX_USER=alice ax inbox # alice's inbox
|
|
||||||
```
|
|
||||||
|
|
||||||
## JSON Output
|
|
||||||
|
|
||||||
All commands support `--json` for machine-readable output:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ax list --status open --json
|
|
||||||
ax show abc12 --json
|
|
||||||
```
|
|
||||||
|
|
||||||
Example output:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"id": "abc12",
|
|
||||||
"title": "Implement feature",
|
|
||||||
"content": "Description here",
|
|
||||||
"created_at": "2026-03-25T10:00:00Z",
|
|
||||||
"updated_at": "2026-03-25T10:00:00Z",
|
|
||||||
"tags": ["_type::issue", "_status::open", "backend"],
|
|
||||||
"relations": {
|
|
||||||
"blocks": ["def34"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
`ax` stores user configuration in a JSON file. It searches for `.axconfig` in the
|
|
||||||
current directory and parent directories (like git finds `.git`), falling back to
|
|
||||||
`~/.config/ax/config.json`.
|
|
||||||
|
|
||||||
**Config file format:**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"user": "alice",
|
|
||||||
"aliases": [
|
|
||||||
{"name": "mywork", "command": "list --namespace myproject", "description": "My tasks"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Database Location
|
|
||||||
|
|
||||||
`ax` searches for `.ax.db` in the current directory and parent directories,
|
|
||||||
similar to how git finds `.git`. This allows you to run commands from any
|
|
||||||
subdirectory.
|
|
||||||
|
|
||||||
## Environment Variables
|
|
||||||
|
|
||||||
| Variable | Description |
|
|
||||||
|----------|-------------|
|
|
||||||
| `AX_USER` | Override current username |
|
|
||||||
| `EDITOR` | Editor for `ax edit` (default: `vi`) |
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
194
USAGE.md
Normal file
194
USAGE.md
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
# Axolotl Usage Reference
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
### `ax init [path]`
|
||||||
|
Create a new `.ax.db` in the specified directory (default: current).
|
||||||
|
|
||||||
|
### `ax add <title> [flags]`
|
||||||
|
| Flag | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `--type` | `issue` (default), `note`, `user`, `namespace` |
|
||||||
|
| `--status` | `open` (default), `done` |
|
||||||
|
| `--prio` | `high`, `medium`, `low` |
|
||||||
|
| `--namespace` | Namespace (default: current user) |
|
||||||
|
| `--tag` | Add tag (repeatable) |
|
||||||
|
| `--due` | Due date |
|
||||||
|
| `--content` | Body text |
|
||||||
|
| `--rel` | Relation `type:id` (repeatable) |
|
||||||
|
|
||||||
|
### `ax update <id> [flags]`
|
||||||
|
| Flag | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `--title` | New title |
|
||||||
|
| `--status` | New status |
|
||||||
|
| `--prio` | New priority |
|
||||||
|
| `--type` | New type |
|
||||||
|
| `--namespace` | Transfer to namespace |
|
||||||
|
| `--assignee` | Assign to user |
|
||||||
|
| `--due` / `--clear-due` | Set or clear due date |
|
||||||
|
| `--content` | New body text |
|
||||||
|
| `--tag` / `--tag-remove` | Add or remove tag |
|
||||||
|
| `--rel` / `--rel-remove` | Add or remove relation `type:id` |
|
||||||
|
|
||||||
|
### `ax show <id>`
|
||||||
|
Display node details.
|
||||||
|
|
||||||
|
### `ax list [flags]`
|
||||||
|
| Flag | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `--type` | Filter by type |
|
||||||
|
| `--status` | Filter by status |
|
||||||
|
| `--prio` | Filter by priority |
|
||||||
|
| `--namespace` | Filter by namespace |
|
||||||
|
| `--tag` | Filter by tag (repeatable) |
|
||||||
|
| `--assignee` | Filter by assignee |
|
||||||
|
| `--mention` | Filter by mention |
|
||||||
|
|
||||||
|
### `ax edit <id>`
|
||||||
|
Open node content in `$EDITOR`.
|
||||||
|
|
||||||
|
### `ax del <id> [-f]`
|
||||||
|
Delete a node. Prompts for confirmation unless `--force`.
|
||||||
|
|
||||||
|
### `ax alias [name] [command]`
|
||||||
|
```bash
|
||||||
|
ax alias # list all aliases
|
||||||
|
ax alias mywork "list --tag work" # create/update alias
|
||||||
|
ax alias del mywork # delete alias
|
||||||
|
```
|
||||||
|
|
||||||
|
**Built-in aliases:** `mine`, `due`, `inbox`
|
||||||
|
|
||||||
|
**Argument expansion:** `$me` → current user, `$@` → all args, `$1`/`$2`/… → positional
|
||||||
|
|
||||||
|
## Relations
|
||||||
|
|
||||||
|
| Type | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `blocks` | Prevents target from closing until this is done |
|
||||||
|
| `subtask` | Marks as subtask of target |
|
||||||
|
| `related` | General association |
|
||||||
|
| `assignee` | Assigns to a user (single-value) |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ax update A --rel blocks:B # A blocks B
|
||||||
|
ax update abc12 --assignee alice # assign to alice
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tags and Properties
|
||||||
|
|
||||||
|
Tags follow the `_key::value` pattern for properties:
|
||||||
|
|
||||||
|
| Property | Values |
|
||||||
|
|----------|--------|
|
||||||
|
| `_type` | `issue`, `note`, `user`, `namespace` |
|
||||||
|
| `_status` | `open`, `done` |
|
||||||
|
| `_prio` | `high`, `medium`, `low` |
|
||||||
|
|
||||||
|
## Mentions and Inbox
|
||||||
|
|
||||||
|
Use `@username` in title or content to add to a user's inbox:
|
||||||
|
```bash
|
||||||
|
ax add "Review PR @alice" # alice gets an inbox entry
|
||||||
|
ax inbox # your inbox
|
||||||
|
AX_USER=alice ax inbox # alice's inbox
|
||||||
|
```
|
||||||
|
|
||||||
|
## JSON Output
|
||||||
|
|
||||||
|
All commands support `--json`:
|
||||||
|
```bash
|
||||||
|
ax list --status open --json
|
||||||
|
ax show abc12 --json
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
`ax` searches upward from CWD for `.axconfig`, falling back to `~/.config/ax/config.json`.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"user": "alice",
|
||||||
|
"aliases": [
|
||||||
|
{"name": "mywork", "command": "list --namespace myproject", "description": "My tasks"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Server Mode
|
||||||
|
|
||||||
|
`ax` can run as a shared HTTP JSON API server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ax serve # starts server on configured host:port (default: 0.0.0.0:7000)
|
||||||
|
```
|
||||||
|
|
||||||
|
The server exposes the same operations (add, list, show, update, delete) over HTTP. Clients connect by setting `remote.host` / `remote.port` in their config — the CLI then transparently routes calls to the server instead of a local database.
|
||||||
|
|
||||||
|
### OIDC Authentication
|
||||||
|
|
||||||
|
The server supports OIDC for authentication. Configure in `.axconfig`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"serve": { "host": "0.0.0.0", "port": 7000 },
|
||||||
|
"oidc": {
|
||||||
|
"issuer": "https://your-idp.example.com",
|
||||||
|
"client_id": "axolotl",
|
||||||
|
"client_secret": "secret",
|
||||||
|
"public_url": "https://ax.example.com",
|
||||||
|
"user_claim": "preferred_username"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Client login:
|
||||||
|
```bash
|
||||||
|
ax login # opens browser for OIDC flow, saves session token
|
||||||
|
```
|
||||||
|
|
||||||
|
Without OIDC configured, the server accepts an `X-Ax-User` header for the username (development/trusted networks only).
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -v ./data:/data g.eliaskohout.de/eliaskohout/axolotl-server:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
The image runs `ax serve` and exposes port 7000. Mount a volume at `/data` to persist the database.
|
||||||
|
|
||||||
|
## Permission Model
|
||||||
|
|
||||||
|
Every node has per-node access control. Permissions are transitive via BFS from the requesting user's own node.
|
||||||
|
|
||||||
|
| Level | Relation | Grants |
|
||||||
|
|-------|----------|--------|
|
||||||
|
| 1 | `can_read` | Read / show / list |
|
||||||
|
| 2 | `can_create_rel` | Create relations pointing to this node |
|
||||||
|
| 3 | `can_write` | Update title, content, tags |
|
||||||
|
| 4 | `has_ownership` | Full control including delete and granting access |
|
||||||
|
|
||||||
|
- Creators automatically get `has_ownership` on nodes they create.
|
||||||
|
- Namespace nodes own regular nodes within them; users own their namespaces.
|
||||||
|
- Deleting an owner cascades to all nodes it owns.
|
||||||
|
- User nodes and namespace nodes are globally readable.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Grant bob read access to a node
|
||||||
|
ax update <bob-user-id> --rel can_read:<node-id>
|
||||||
|
|
||||||
|
# Grant bob write access
|
||||||
|
ax update <bob-user-id> --rel can_write:<node-id>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
| Variable | Description |
|
||||||
|
|----------|-------------|
|
||||||
|
| `AX_USER` | Override current username |
|
||||||
|
| `EDITOR` | Editor for `ax edit` (default: `vi`) |
|
||||||
|
|
||||||
|
## Database Location
|
||||||
|
|
||||||
|
`ax` searches for `.ax.db` upward from CWD (like git finds `.git`), so commands work from any subdirectory.
|
||||||
Reference in New Issue
Block a user