A standalone CLI for AFFiNE — manage workspaces, documents, databases, tables, comments, tags, and more from your terminal.
Built for self-hosted AFFiNE instances. Works with both email/password authentication and API tokens.
- Document operations — create, read, export, append, replace via Markdown
- Rich text support — bold, italic, code, strikethrough, links rendered natively in AFFiNE
- Markdown tables —
| col | col |syntax converted to nativeaffine:tableblocks - Database blocks — create databases with typed columns and rows
- Tags, comments, blobs, notifications — full CRUD
- Structured JSON output — pipe-friendly, with
--fieldsfiltering - Dry-run mode — preview destructive operations before executing
- AI-agent friendly —
affine schemaoutputs full JSON Schema for all commands
go install github.com/tomohiro-owada/affine-cli@latestgit clone https://github.com/tomohiro-owada/affine-cli.git cd affine-cli go build -o affine .Set credentials via environment variables:
export AFFINE_BASE_URL=https://your-affine-instance.com export AFFINE_EMAIL=you@example.com export AFFINE_PASSWORD=your-password export AFFINE_WORKSPACE_ID=your-workspace-uuidOr use an API token:
export AFFINE_BASE_URL=https://your-affine-instance.com export AFFINE_API_TOKEN=your-token export AFFINE_WORKSPACE_ID=your-workspace-uuidConfig file is also supported at ~/.config/affine-mcp/config (key=value format). Environment variables take precedence.
# Check authentication affine auth status # List workspaces affine workspace list # List documents affine doc list --fields id,title # Create a document from Markdown affine doc create-from-markdown --title "Hello" --content "# Hello World This is a **bold** and *italic* text. | Name | Score | |------|-------| | Alice | 100 | | Bob | 95 | " # Read a document affine doc read --doc-id <DOC_ID> # Export as Markdown affine doc export-markdown --doc-id <DOC_ID>affine workspace list # List all workspaces affine workspace get # Get workspace details affine workspace create --init <file> # Create workspace affine workspace update --public --enable-ai # Update settings affine workspace delete # Delete workspaceaffine doc list [--first N] [--offset N] # List documents affine doc get --doc-id ID # Get document metadata affine doc create --title "Title" # Create empty document affine doc create-from-markdown --title T --content M # Create from Markdown affine doc read --doc-id ID # Read document blocks affine doc export-markdown --doc-id ID # Export as Markdown affine doc append-paragraph --doc-id ID --text T # Append text affine doc append-markdown --doc-id ID --content M # Append Markdown affine doc replace-markdown --doc-id ID --content M # Replace with Markdown affine doc delete --doc-id ID # Delete document affine doc publish --doc-id ID [--mode Page|Edgeless] # Publish affine doc revoke --doc-id ID # Revoke publicationaffine db create --doc-id ID --title T --columns "Name,Status" # Create database affine db add-column --doc-id ID --db-block-id B --name N # Add column affine db add-row --doc-id ID --db-block-id B --cells '{"col-id":"value"}' # Add rowaffine table add-row --doc-id ID --block-id B --cells "val1,val2" # Add row to tableTables are also created automatically from Markdown table syntax in create-from-markdown and append-markdown.
affine tag list # List all tags affine tag create --name "Tag" --color blue # Create tag affine tag add --doc-id ID --tag-id T # Add tag to document affine tag remove --doc-id ID --tag-id T # Remove tag affine tag list-docs --tag-id T # List docs with tagaffine comment list --doc-id ID # List comments affine comment create --doc-id ID --content "text" # Create comment affine comment update --id ID --content "new" # Update comment affine comment delete --id ID # Delete comment affine comment resolve --id ID --resolved # Resolve commentaffine auth status # Check auth status affine auth sign-in --email E --password P # Sign in affine user me # Current user info affine user update-profile --name "Name" # Update profile affine user update-settings --receive-comment-notification # Update settingsaffine notification list [--first N] # List notifications affine notification read-all # Mark all as readaffine token list # List tokens affine token generate --name "name" # Generate token affine token revoke --id ID # Revoke tokenaffine blob upload --file path/to/file # Upload file affine blob delete --key KEY [--permanently] # Delete blob affine blob cleanup # Release deleted blobsaffine history list --doc-id ID [--take N] # List doc history| Flag | Description |
|---|---|
-w, --workspace | Workspace ID (overrides AFFINE_WORKSPACE_ID) |
--dry-run | Preview destructive operations without executing |
--fields | Filter output fields (e.g., --fields id,title) |
--json | Read structured JSON input from stdin |
affine-cli/ ├── cmd/ # Cobra command definitions ├── internal/ │ ├── auth/ # Email/password sign-in │ ├── config/ # Configuration loading (env, file) │ ├── docops/ # Document operations (Y.js CRDT via Socket.io) │ ├── graphql/ # GraphQL client and queries │ ├── output/ # JSON output formatting │ ├── socketio/ # Socket.io v4 client │ ├── validate/ # Input validation │ └── yjs/ # Y.js engine (goja runtime with embedded yjs bundle) ├── AGENTS.md # AI agent integration guide ├── main.go └── README.md - Metadata operations (list, get, publish, comments, etc.) use GraphQL against the AFFiNE server API
- Document content operations (create, read, append, replace) use Socket.io to connect to the real-time sync protocol and manipulate Y.js CRDT documents directly
- Y.js engine runs in a goja JavaScript runtime with an embedded Y.js bundle, enabling Go code to create and modify CRDT documents
- Rich text is stored as
Y.Textwith attributes (bold,italic,code,strike,link) matching AFFiNE/BlockSuite format - Tables use AFFiNE's flat-key format (
prop:rows.{id}.order,prop:cells.{rowId}:{colId}.text) withY.Textcell values
This CLI is designed to be used by AI agents. Run affine schema to get a machine-readable JSON Schema of all commands and their parameters.
See AGENTS.md for the full AI agent integration guide.
Unit tests:
go test ./...Integration tests (requires a running AFFiNE instance):
export AFFINE_BASE_URL=https://your-instance.com export AFFINE_EMAIL=test@example.com export AFFINE_PASSWORD=password export AFFINE_WORKSPACE_ID=your-workspace-id go test -tags=integration -v .