@tailor-app/cli
v0.10.0
Published
Tailor Documents CLI — upload, share, and manage documents from your terminal
Maintainers
Readme
Tailor CLI
Command-line tool for uploading, sharing, and managing documents on Tailor.
Quickstart
npm install -g @tailor-app/cli
tailor login --email [email protected]
tailor upload ./my-document.docx --shareInstallation
From npm (recommended)
npm install -g @tailor-app/cli
tailor --helpRequires Node.js 20+.
From the repo (development)
cd tools/tailor-cli
npm install
npm run buildRun commands via node bin/tailor.js <command> or set up a shell alias.
Authentication
The CLI uses API keys for authentication. Keys are prefixed with tailor_sk_ and sent as X-Api-Key headers.
For AI agents and CI/CD (recommended)
Set an environment variable — no tailor login needed:
export TAILOR_API_KEY=tailor_sk_your_key
tailor list # works immediatelyOptionally set the base URL (defaults to https://tailor.au):
export TAILOR_BASE_URL=https://tailor.auEnvironment variables take precedence over stored configuration.
Store a key to disk
tailor login --key tailor_sk_your_key --url https://tailor.auVerify current auth
tailor login --checkInteractive login (humans only)
tailor login --email [email protected]Note:
tailor loginwithout flags is interactive and requires a terminal. In non-TTY environments (CI, AI agents), it prints guidance and exits.
Command Reference
tailor login
Configure API key and base URL for the CLI.
tailor login --key tailor_sk_abc123 # Store API key
tailor login --key tailor_sk_abc123 --url https://tailor.au
tailor login --check # Verify current auth
tailor login --email [email protected] # Interactive magic link
tailor login # Fully interactive (TTY only)Options:
| Flag | Description | Default |
|------|-------------|---------|
| --key <apiKey> | API key (must start with tailor_sk_) | — |
| --url <baseUrl> | Base URL for the Tailor API | https://tailor.au |
| --check | Validate current auth and exit (no prompts) | — |
| --email <email> | Account email for magic link auth | — |
| --code-only | Skip browser auth, use code entry only | — |
tailor upload <files...>
Upload one or more documents. Supports files, folders, and glob patterns.
tailor upload ./report.docx
tailor upload ./report.md
tailor upload ./docs/ # upload all supported files in folder (recursive)
tailor upload ./docs/*.docx
tailor upload ./deliverables/*.docx --share --public
tailor upload ./budget.xlsx --share --permission CommentOnly
tailor upload ./docs/*.docx --jsonWhen a folder is passed, it is scanned recursively for supported file types (.docx, .pdf, .html, .htm, .md).
Arguments:
| Argument | Description |
|----------|-------------|
| <files...> | One or more file paths, folder paths, or glob patterns |
Options:
| Flag | Description | Default |
|------|-------------|---------|
| --share | Create shareable links after upload | false |
| --permission <perm> | Share permission: ReadOnly, CommentOnly, FullReview | ReadOnly |
| --public | Public links (no email verification) | false |
| --json | Output results as JSON | false |
tailor share <documentId>
Create a shareable link for an existing document.
tailor share a1b2c3d4-e5f6-7890-abcd-ef1234567890
tailor share a1b2c3d4 --permission FullReview
tailor share a1b2c3d4 --publicArguments:
| Argument | Description |
|----------|-------------|
| <documentId> | Document ID (GUID) |
Options:
| Flag | Description | Default |
|------|-------------|---------|
| --permission <perm> | ReadOnly, CommentOnly, FullReview | ReadOnly |
| --public | No email verification required | false |
tailor list
List all your documents.
tailor list
tailor list --jsonOptions:
| Flag | Description | Default |
|------|-------------|---------|
| --json | Output as JSON | false |
tailor keys create
Create a new API key.
tailor keys create --name "CI Pipeline"
tailor keys create --name "LCC Upload" --scopes "documents:read,documents:write"
tailor keys create --name "Temp Key" --expires 30Options:
| Flag | Description | Default |
|------|-------------|---------|
| --name <name> | Key name (required) | — |
| --scopes <scopes> | Comma-separated scopes | documents:read,documents:write |
| --expires <days> | Days until expiry | 365 |
tailor keys list
List all active API keys.
tailor keys listtailor keys revoke
Revoke an API key.
tailor keys revoke key_abc123tailor tap — PACT Protocol
Collaborate on documents at machine speed. The tap command group lets AI agents join documents, propose edits, review proposals, and coordinate via the PACT protocol.
Command Reference
| Command | Description |
|---------|-------------|
| tailor tap join <docId> --as <name> | Register as an agent on a document |
| tailor tap leave <docId> | Unregister from a document |
| tailor tap get <docId> | Get document content (Markdown, HTML, or DOCX text) |
| tailor tap sections <docId> | Show section tree with stable IDs (.md, .html, .docx) |
| tailor tap propose <docId> --section <id> | Propose an edit to a section |
| tailor tap proposals <docId> | List active proposals |
| tailor tap approve <docId> <proposalId> | Approve a proposal |
| tailor tap reject <docId> <proposalId> --reason <text> | Reject a proposal |
| tailor tap agents <docId> | List active agents |
| tailor tap escalate <docId> --message <text> | Escalate to human reviewer |
| tailor tap events <docId> | View event history |
| tailor tap lock <docId> --section <id> | Lock a section for editing |
| tailor tap unlock <docId> --section <id> | Unlock a section |
| tailor tap intent <docId> --section <id> --goal <text> | Declare an intent on a section |
| tailor tap intents <docId> | List intents on a document |
| tailor tap constrain <docId> --section <id> --boundary <text> | Publish a constraint |
| tailor tap constraints <docId> | List constraints on a document |
| tailor tap salience <docId> --section <id> --score <0-10> | Set salience score for a section |
| tailor tap salience-map <docId> | View salience heat map |
| tailor tap object <docId> --proposal <id> --reason <text> | Object to a proposal |
Supported Document Formats
PACT works with any document format Tailor supports:
| Format | Section Parsing | Proposals | Content Retrieval |
|--------|----------------|-----------|-------------------|
| Markdown (.md) | ✅ ATX headings | ✅ Full | ✅ Raw Markdown |
| HTML (.html) | ✅ <h1>–<h6> tags | ✅ Full | ✅ Raw HTML |
| DOCX (.docx) | ✅ Word heading styles | ✅ Full | ✅ Text projection |
| PDF (.pdf) | ✅ Via DOCX conversion | ✅ Full | ✅ Text projection |
All formats produce the same sec:slug/child-slug section IDs, so agents interact identically regardless of source format.
tailor tap join
tailor tap join abc123 --as "legal-reviewer" --role reviewer| Flag | Description | Required |
|------|-------------|----------|
| --as <agentName> | Agent name | Yes |
| --role <role> | Agent role | No |
tailor tap get
Outputs document content to stdout so it can be piped. For Markdown and HTML, raw source is returned; for DOCX and PDF, a text projection is returned:
tailor tap get abc123 > document.md
tailor tap get abc123 --section sec_01 | head -20| Flag | Description | Required |
|------|-------------|----------|
| --section <sectionId> | Get single section | No |
tailor tap propose
Propose a change using a file or inline content:
# From a file
tailor tap propose abc123 --section sec_01 --file ./revised-intro.md --summary "Tightened intro"
# Inline content
tailor tap propose abc123 --section sec_01 --content "New paragraph text" --summary "Fixed typo"| Flag | Description | Required |
|------|-------------|----------|
| --section <sectionId> | Target section | Yes |
| --file <path> | Read content from file | One of --file / --content |
| --content <text> | Inline content | One of --file / --content |
| --summary <text> | Change summary | No |
| --reasoning <text> | Reasoning for change | No |
tailor tap proposals
tailor tap proposals abc123
tailor tap proposals abc123 --section sec_01 --status pending --json| Flag | Description | Required |
|------|-------------|----------|
| --section <sectionId> | Filter by section | No |
| --status <status> | Filter by status | No |
| --json | Output as JSON | No |
tailor tap lock / unlock
tailor tap lock abc123 --section sec_01 --ttl 60
tailor tap unlock abc123 --section sec_01| Flag | Description | Default |
|------|-------------|---------|
| --section <sectionId> | Section to lock/unlock | Required |
| --ttl <seconds> | Lock time-to-live | 30 |
tailor tap intent
Declare what you want to achieve in a section — before writing any text:
tailor tap intent abc123 --section sec:liability --goal "Add currency risk language" --category compliance| Flag | Description | Required |
|------|-------------|----------|
| --section <sectionId> | Target section | Yes |
| --goal <text> | What you want to achieve | Yes |
| --category <category> | e.g. compliance, clarity, structure | No |
tailor tap intents
tailor tap intents abc123
tailor tap intents abc123 --section sec:liability --json| Flag | Description | Required |
|------|-------------|----------|
| --section <sectionId> | Filter by section | No |
| --json | Output as JSON | No |
tailor tap constrain
Publish a boundary condition — what must or must not happen:
tailor tap constrain abc123 --section sec:liability --boundary "Liability cap must not exceed $2M" --category commercial| Flag | Description | Required |
|------|-------------|----------|
| --section <sectionId> | Target section | Yes |
| --boundary <text> | Boundary condition | Yes |
| --category <category> | e.g. regulatory, commercial, technical | No |
tailor tap constraints
tailor tap constraints abc123
tailor tap constraints abc123 --section sec:liability --json| Flag | Description | Required |
|------|-------------|----------|
| --section <sectionId> | Filter by section | No |
| --json | Output as JSON | No |
tailor tap salience
Signal how much you care about a section (0 = don't care, 10 = critical):
tailor tap salience abc123 --section sec:liability --score 9| Flag | Description | Required |
|------|-------------|----------|
| --section <sectionId> | Target section | Yes |
| --score <0-10> | Salience score | Yes |
tailor tap salience-map
View the salience heat map showing where agent attention is concentrated:
tailor tap salience-map abc123
tailor tap salience-map abc123 --json| Flag | Description | Required |
|------|-------------|----------|
| --json | Output as JSON | No |
tailor tap object
Object to a proposal (objection-based merge — silence = consent):
tailor tap object abc123 --proposal prop_xyz --reason "Violates liability cap constraint"| Flag | Description | Required |
|------|-------------|----------|
| --proposal <proposalId> | Proposal to object to | Yes |
| --reason <text> | Reason for objection | Yes |
Agent Workflow Example
# 1. Join the document
tailor tap join abc123 --as "legal-reviewer" --role reviewer
# 2. Read the document
tailor tap get abc123 > doc.md
# 3. View sections
tailor tap sections abc123
# 4. Lock, propose, unlock
tailor tap lock abc123 --section sec_01 --ttl 60
tailor tap propose abc123 --section sec_01 --file ./revised.md --summary "Compliance fix"
tailor tap unlock abc123 --section sec_01
# 5. Another agent approves
tailor tap approve abc123 prop_abc
# 6. Leave when done
tailor tap leave abc123Multi-Agent Example
# Agent A joins as editor
tailor tap join abc123 --as "editor-agent" --role editor
# Agent B joins as reviewer
tailor tap join abc123 --as "review-agent" --role reviewer
# Agent A proposes an edit
tailor tap propose abc123 --section sec_02 --file ./rewrite.md --summary "Rewrite methodology"
# Agent B reviews and approves
tailor tap proposals abc123 --section sec_02
tailor tap approve abc123 prop_xyz
# If stuck, escalate to human
tailor tap escalate abc123 --section sec_03 --message "Legal clause needs human review"Intent-Constraint-Salience (ICS) Example
Align before you write — critical when agents have confidential contexts:
# Agent A (legal): Declare intent — tells everyone WHAT, not WHY
tailor tap intent abc123 --section sec:liability \
--goal "Add currency risk allocation language" --category legal
# Agent B (commercial): Publish constraint — sets boundaries
tailor tap constrain abc123 --section sec:liability \
--boundary "Total liability must not exceed $2M AUD" --category commercial
# Agent C (compliance): Set salience — signal this section is critical
tailor tap salience abc123 --section sec:liability --score 10
# Agent A: Check constraints before writing
tailor tap constraints abc123 --section sec:liability
tailor tap salience-map abc123
# Agent A: Propose text satisfying all constraints
tailor tap propose abc123 --section sec:liability \
--file ./revised-liability.md \
--summary "Currency risk clause — within $2M cap, references CPS 230"
# If silence (no objections) → auto-merges after TTL
# If Agent B disagrees:
tailor tap object abc123 --proposal prop_xyz \
--reason "Currency risk exposure exceeds the $2M liability cap"
# Escalate to human if agents can't resolve
tailor tap escalate abc123 --section sec:liability \
--message "Agents disagree on liability cap vs. currency risk allocation"BYOK Invite Flow — Connect External Agents
PACT uses a BYOK (Bring Your Own Key) model. Document owners create scoped invite tokens for external AI agents. Agents join anonymously — no Tailor account needed.
# 1. Create an invite (you are the document owner)
tailor tap invite create DOC_ID --label "Legal Review Agent" --context-mode SectionScoped --expires 24h
# → Token: a1b2c3d4e5f6... (give this to the external agent)
# 2. External agent joins anonymously:
curl -X POST https://tailor.au/api/tap/DOC_ID/join-token \
-H "Content-Type: application/json" \
-d '{"agentName": "legal-bot", "token": "a1b2c3d4e5f6..."}'
# → { registrationId, apiKey: "tailor_sk_scoped_...", contextMode, allowedSections }
# 3. Agent uses the scoped key for all PACT operationsInvite options:
| Flag | Description | Default |
|------|-------------|---------|
| --label <name> | Human-readable label | Required |
| --context-mode <mode> | Full, SectionScoped, Neighbourhood, SummaryOnly | Full |
| --allowed-sections <ids> | Comma-separated section IDs | All |
| --max-agents <n> | Max concurrent agents per invite | Unlimited |
| --expires <duration> | Expiry (e.g., 24h, 7d) | None |
| --role <role> | Pre-assigned role (editor, reviewer, observer) | None |
| --webhook <url> | POST callback when an agent joins | None |
MCP Server (stdio)
For MCP-compatible agents (Cursor, Claude Desktop, Windsurf):
{
"mcpServers": {
"tailor": {
"command": "npx",
"args": ["-y", "@tailor-app/cli", "mcp", "serve"],
"env": {
"TAILOR_API_KEY": "<scoped-key-from-join-token>",
"TAILOR_BASE_URL": "https://tailor.au"
}
}
}
}HTTP MCP Endpoint
For remote/cloud agents (Claude API, server-side agents):
- Endpoint:
https://tailor.au/mcp(streamable HTTP) - Discovery:
https://tailor.au/.well-known/mcp.json - Auth:
X-Api-Keyheader with scoped key fromjoin-token
OpenAI GPT Actions
Import the PACT-focused OpenAPI spec into a Custom GPT:
- GPT Builder > Configure > Actions > Import from URL
- Enter:
https://tailor.au/openapi/tap.json - Auth: API Key, header
X-Api-Key, value = scoped key fromjoin-token
Examples
LCC Quickstart: Upload 26 deliverables with shareable links
# Configure for production
tailor login --key tailor_sk_lcc_production_key
# Upload all DOCX files and generate public share links
tailor upload ./deliverables/*.docx --share --public
# Output:
# Uploading 26 file(s)...
#
# ✓ LCC-Policy-Report.docx → a1b2c3d4
# https://tailor.au/share/abc123...
# ✓ LCC-Budget-Analysis.docx → e5f6g7h8
# https://tailor.au/share/def456...
# ...
# ✓ 26/26 uploaded successfully
#
# Shareable Links:
# LCC-Policy-Report: https://tailor.au/share/abc123...
# LCC-Budget-Analysis: https://tailor.au/share/def456...Upload Markdown files
# Upload a single Markdown file
tailor upload ./report.md --share
# Upload all Markdown files in a directory
tailor upload ./docs/*.md --share --publicMarkdown files are converted to HTML on upload for preview, with the original .md preserved as the source of truth.
CI/CD Integration
# Set credentials via environment variables
export TAILOR_API_KEY=tailor_sk_ci_key
export TAILOR_BASE_URL=https://tailor.au
# Upload build artifacts
tailor upload ./output/*.docx --share --json > upload-results.jsonLocal Development
# Point to local API
tailor login --url http://localhost:7255 --key tailor_sk_dev_key
# Upload a test document
tailor upload ./test-fixtures/demo.docx
# List documents
tailor list --jsonShare with specific permissions
# Read-only share (default)
tailor share abc123
# Allow comments
tailor share abc123 --permission CommentOnly
# Full review access, no email verification
tailor share abc123 --permission FullReview --publicEnvironment Variables
| Variable | Description | Default |
|----------|-------------|---------|
| TAILOR_API_KEY | API key for authentication | — |
| TAILOR_BASE_URL | Base URL for the Tailor API | https://tailor.au |
Environment variables override stored configuration.
Config Storage
Configuration is stored locally using the conf package:
- Windows:
%APPDATA%/tailor-cli/config.json - macOS:
~/Library/Preferences/tailor-cli/config.json - Linux:
~/.config/tailor-cli/config.json
Run tailor login to see the exact path.
Troubleshooting
| Problem | Cause | Fix |
|---------|-------|-----|
| Not authenticated | No API key configured | Run tailor login --key tailor_sk_... or set TAILOR_API_KEY env var |
| HTTP 401: Unauthorized | Session expired or invalid key | Re-authenticate: tailor login --email <email> or tailor login --key <key> |
| HTTP 403: Forbidden | Key lacks required scopes | Create a new key: tailor keys create --name "agent" --scopes "documents:read,documents:write" |
| Could not connect to https://tailor.au | Wrong URL or server unreachable | Check URL: tailor login --url <url>. For local dev: http://localhost:7255 |
| Server returned HTML | Base URL points to web app, not API | Verify TAILOR_BASE_URL doesn't include a path (should be just https://tailor.au) |
| Section not found | Section ID changed or is invalid | Run tailor tap sections <docId> to list current valid section IDs |
| Lock failed | Section already locked by another agent | Wait for TTL expiry or check tailor tap sections <docId> for lock info |
| Already joined | Agent already registered on the document | Run tailor tap leave <docId> first, then re-join |
| Proposal stuck in pending | Waiting for approvals per policy | Check the document's ApprovalPolicy. Use objection-based merge for faster flow |
| ENOENT on upload | File path doesn't exist | Check the file path. Use quotes around paths with spaces |
| Commands not found after update | Old version cached | Run npm cache clean --force && npm install -g @tailor-app/cli |
For more detailed debugging, see the PACT Getting Started Guide.
Requirements
- Node.js >= 20.0.0
- A Tailor account with an API key
Tech Stack
- Commander.js — CLI framework
- chalk — Terminal colors
- ora — Terminal spinners
- conf — Persistent config
- glob — File pattern matching
