Tangled CLI – Current Implementation Status#
This document provides an overview of the Tangled CLI implementation status for AI agents or developers working on the project.
Implementation Status#
✅ Fully Implemented#
Authentication (auth)#
login- Authenticate with AT Protocol usingcom.atproto.server.createSessionstatus- Show current authentication statuslogout- Clear stored session from keyring
Repositories (repo)#
list- List repositories usingcom.atproto.repo.listRecordswithcollection=sh.tangled.repocreate- Create repositories with two-step flow:- Create PDS record via
com.atproto.repo.createRecord - Initialize bare repo via
sh.tangled.repo.createwith ServiceAuth
- Create PDS record via
clone- Clone repositories using libgit2 with SSH agent supportinfo- Display repository information including stats and languagesdelete- Delete repositories (both PDS record and knot repo)star/unstar- Star/unstar repositories viash.tangled.feed.star
Issues (issue)#
list- List issues viacom.atproto.repo.listRecordswithcollection=sh.tangled.repo.issuecreate- Create issues viacom.atproto.repo.createRecordshow- Show issue details and commentsedit- Edit issue title, body, or statecomment- Add comments to issues
Pull Requests (pr)#
list- List PRs viacom.atproto.repo.listRecordswithcollection=sh.tangled.repo.pullcreate- Create PRs usinggit format-patchfor patchesshow- Show PR details and diffreview- Review PRs with approve/request-changes flagsmerge- Merge PRs viash.tangled.repo.mergewith ServiceAuth
Knot Management (knot)#
migrate- Migrate repositories between knots- Validates working tree is clean and pushed
- Creates new repo on target knot with source seeding
- Updates PDS record to point to new knot
Spindle CI/CD (spindle)#
config- Enable/disable or configure spindle URL for a repository- Updates the
spindlefield insh.tangled.reporecord
- Updates the
list- List pipeline runs viacom.atproto.repo.listRecordswithcollection=sh.tangled.pipelinelogs- Stream workflow logs via WebSocket (wss://spindle.tangled.sh/spindle/logs/{knot}/{rkey}/{name})secret list- List secrets viash.tangled.repo.listSecretswith ServiceAuthsecret add- Add secrets viash.tangled.repo.addSecretwith ServiceAuthsecret remove- Remove secrets viash.tangled.repo.removeSecretwith ServiceAuth
🚧 Partially Implemented / Stubs#
Spindle CI/CD (spindle)#
run- Manually trigger a workflow (stub)- TODO: Parse
.tangled.ymlto determine workflows - TODO: Create pipeline record and trigger spindle ingestion
- TODO: Support manual trigger inputs
- TODO: Parse
Architecture Overview#
Workspace Structure#
crates/tangled-cli- CLI binary with clap-based argument parsingcrates/tangled-config- Configuration and keyring-backed session managementcrates/tangled-api- XRPC client wrapper for AT Protocol and Tangled APIscrates/tangled-git- Git operation helpers (currently unused)
Key Patterns#
ServiceAuth Flow#
Many Tangled API operations require ServiceAuth tokens:
- Obtain token via
com.atproto.server.getServiceAuthfrom PDSaudparameter must bedid:web:<target-host>expparameter should be Unix timestamp + 600 seconds
- Use token as
Authorization: Bearer <serviceAuth>for Tangled API calls
Repository Creation Flow#
Two-step process:
- PDS: Create
sh.tangled.reporecord viacom.atproto.repo.createRecord - Tangled API: Initialize bare repo via
sh.tangled.repo.createwith ServiceAuth
Repository Listing#
Done entirely via PDS (not Tangled API):
- Resolve handle → DID if needed via
com.atproto.identity.resolveHandle - List records via
com.atproto.repo.listRecordswithcollection=sh.tangled.repo - Filter client-side (e.g., by knot)
Pull Request Merging#
- Fetch PR record to get patch and target branch
- Obtain ServiceAuth token
- Call
sh.tangled.repo.mergewith{did, name, patch, branch, commitMessage, commitBody}
Base URLs and Defaults#
- PDS Base (auth + record operations): Default
https://bsky.social, stored in session - Tangled API Base (server operations): Default
https://tngl.sh, can override viaTANGLED_API_BASE - Spindle Base (CI/CD): Default
wss://spindle.tangled.shfor WebSocket logs, can override viaTANGLED_SPINDLE_BASE
Session Management#
Sessions are stored in the system keyring:
- Linux: GNOME Keyring / KWallet via Secret Service API
- macOS: macOS Keychain
- Windows: Windows Credential Manager
Session includes:
struct Session {
access_jwt: String,
refresh_jwt: String,
did: String,
handle: String,
pds: Option<String>, // PDS base URL
}
Working with tangled-core#
The ../tangled-core repository contains the server implementation and lexicon definitions.
Key Files to Check#
-
Lexicons:
../tangled-core/lexicons/**/*.json- Defines XRPC method schemas (NSIDs, parameters, responses)
- Example:
sh.tangled.repo.create,sh.tangled.repo.merge
-
XRPC Routes:
../tangled-core/knotserver/xrpc/xrpc.go- Shows which endpoints require ServiceAuth
- Maps NSIDs to handler functions
-
API Handlers:
../tangled-core/knotserver/xrpc/*.go- Implementation details for server-side operations
- Example:
create_repo.go,merge.go
Useful Search Commands#
# Find a specific NSID
rg -n "sh\.tangled\.repo\.create" ../tangled-core
# List all lexicons
ls ../tangled-core/lexicons/repo
# Check ServiceAuth usage
rg -n "ServiceAuth|VerifyServiceAuth" ../tangled-core
Next Steps for Contributors#
Priority: Implement spindle run#
The only remaining stub is spindle run for manually triggering workflows. Implementation plan:
-
Parse
.tangled.ymlin the current repository to extract workflow definitions- Look for workflow names, triggers, and manual trigger inputs
-
Create pipeline record on PDS via
com.atproto.repo.createRecord:collection: "sh.tangled.pipeline" record: { triggerMetadata: { kind: "manual", repo: { knot, did, repo, defaultBranch }, manual: { inputs: [...] } }, workflows: [{ name, engine, clone, raw }] } -
Notify spindle (if needed) or let the ingester pick up the new record
-
Support workflow selection when multiple workflows exist:
--workflow <name>flag to select specific workflow- Default to first workflow if not specified
-
Support manual inputs (if workflow defines them):
- Prompt for input values or accept via flags
Code Quality Tasks#
- Add more comprehensive error messages for common failure cases
- Improve table formatting for list commands (consider using
tabledcrate features) - Add shell completion generation (bash, zsh, fish)
- Add more unit tests with
mockitofor API client methods - Add integration tests with
assert_cmdfor CLI commands
Documentation Tasks#
- Add man pages for all commands
- Create video tutorials for common workflows
- Add troubleshooting guide for common issues
Development Workflow#
Building#
cargo build # Debug build
cargo build --release # Release build
Running#
cargo run -p tangled-cli -- <command>
Testing#
cargo test # Run all tests
cargo test -- --nocapture # Show println output
Code Quality#
cargo fmt # Format code
cargo clippy # Run linter
cargo clippy -- -W clippy::all # Strict linting
Troubleshooting Common Issues#
Keyring Errors on Linux#
Ensure a secret service is running:
systemctl --user enable --now gnome-keyring-daemon
Invalid Token Errors#
- For record operations: Use PDS client, not Tangled API client
- For server operations: Ensure ServiceAuth audience DID matches target host
Repository Not Found#
- Verify repo exists:
tangled repo info owner/name - Check you're using the correct owner (handle or DID)
- Ensure you have access permissions
WebSocket Connection Failures#
- Check spindle base URL is correct (default:
wss://spindle.tangled.sh) - Verify the job_id format:
knot:rkey:name - Ensure the workflow has actually run and has logs
Additional Resources#
- Main README:
README.md- User-facing documentation - Getting Started Guide:
docs/getting-started.md- Tutorial for new users - Lexicons:
../tangled-core/lexicons/- XRPC method definitions - Server Implementation:
../tangled-core/knotserver/- Server-side code
Last updated: 2025-10-14