Tangled CLI #
Part of the overby.me monorepo, where this lives in
platform/tangled/cliand where all development happens.It is also published on its own, as tangled.org/overby.me/tangled-cli and github.com/overby-me/tangled-cli. Both are read-only mirrors, rebuilt from the monorepo with josh: a commit made to either is overwritten by the next sync, so please open issues and pull requests on the monorepo.
A Rust CLI for Tangled, a decentralized git collaboration platform built on the AT Protocol.
Features #
Tangled CLI is a fully functional tool for managing repositories, issues, pull requests, and CI/CD workflows on the Tangled platform.
Implemented Commands #
-
Authentication (
auth)login- Authenticate with AT Protocol credentialsstatus- Show current authentication statuslogout- Clear stored session
-
Repositories (
repo)list- List your repositories or another user's reposcreate- Create a new repository on a knotclone- Clone a repository to your local machineinfo- Show detailed repository informationdelete- Delete a repositorystar/unstar- Star or unstar repositories
-
Issues (
issue)list- List issues for a repositorycreate- Create a new issueshow- Show issue details and commentsedit- Edit issue title, body, or statecomment- Add a comment to an issue
-
Pull Requests (
pr)list- List pull requests for a repositorycreate- Create a pull request from a branchshow- Show pull request details and diffreview- Review a pull request (approve/request changes)merge- Merge a pull request
-
Knot Management (
knot)migrate- Migrate a repository to another knot
-
CI/CD with Spindle (
spindle)config- Enable/disable or configure spindle for a repositorylist- List pipeline runs for a repositorylogs- Stream logs from a workflow executionsecret- Manage secrets for CI/CD workflowslist- List secrets for a repositoryadd- Add or update a secretremove- Remove a secret
run- Manually trigger a workflow (not yet implemented)
Installation #
Build from Source #
Requires Rust toolchain (1.70+) and network access to fetch dependencies.
cargo build --release
The binary will be available at target/release/tangled-cli.
Install from AUR (Arch Linux) #
Community-maintained package:
yay -S tangled-cli-git
Quick Start #
-
Login to Tangled:
tangled auth login --handle your.handle.bsky.social -
List your repositories:
tangled repo list -
Create a new repository:
tangled repo create myproject --description "My cool project" -
Clone a repository:
tangled repo clone username/reponame
Workspace Structure #
crates/tangled-cli- CLI binary with clap-based argument parsingcrates/tangled-config- Configuration and session management (keyring-backed)crates/tangled-api- XRPC client wrapper for AT Protocol and Tangled APIscrates/tangled-git- Git operation helpers
Configuration #
The CLI stores session credentials securely in your system keyring and configuration in:
- Linux:
~/.config/tangled/config.toml - macOS:
~/Library/Application Support/tangled/config.toml - Windows:
%APPDATA%\tangled\config.toml
Environment Variables #
TANGLED_PDS_BASE- Override the PDS base URL (default:https://bsky.social)TANGLED_API_BASE- Override the Tangled API base URL (default:https://tngl.sh)TANGLED_SPINDLE_BASE- Override the Spindle base URL (default:wss://spindle.tangled.sh)
Examples #
Working with Issues #
# Create an issue
tangled issue create --repo myrepo --title "Bug: Fix login" --body "Description here"
# List issues
tangled issue list --repo myrepo
# Comment on an issue
tangled issue comment <issue-id> --body "I'll fix this"
Working with Pull Requests #
# Create a PR from a branch
tangled pr create --repo myrepo --base main --head feature-branch --title "Add new feature"
# Review a PR
tangled pr review <pr-id> --approve --comment "LGTM!"
# Merge a PR
tangled pr merge <pr-id>
CI/CD with Spindle #
# Enable spindle for your repo
tangled spindle config --repo myrepo --enable
# List pipeline runs
tangled spindle list --repo myrepo
# Stream logs from a workflow
tangled spindle logs knot:rkey:workflow-name --follow
# Manage secrets
tangled spindle secret add --repo myrepo --key API_KEY --value "secret-value"
tangled spindle secret list --repo myrepo
Development #
Run tests:
cargo test
Run with debug output:
cargo run -p tangled-cli -- --verbose <command>
Format code:
cargo fmt
Check for issues:
cargo clippy
Lexicon audit #
This tree is a vendored fork, and Tangled's lexicons move. Auditing it against
aly.codes/tg, which tracks them closely,
found nine defects that all looked like working code:
| What | Symptom |
|---|---|
sh.tangled.spindle.listRuns no longer exists |
spindle runs/logs died with a bare 404; the namespace is sh.tangled.ci |
sh.tangled.repo.pull.state renamed to .status |
closing a pull wrote a record nothing reads; merged was inexpressible |
Records missing required createdAt/$type |
written with validate: false, so the PDS accepted them and the appview ignored them |
| Listing by scanning a PDS | one undeserialisable record failed the whole response; capped at 100; could not see another account's repos |
cancel parsed an empty body as JSON |
every cancel failed with EOF while parsing a value |
sh.tangled.pipeline is dead |
spindle list read a collection with zero records |
| Star subject written flat | repo star wrote records countStars never counted |
get_repo_info scanned the caller's PDS |
another owner's repo was Could not find repo |
pr diff read a patch field |
the field does not exist: the patch is a gzipped blob CID under rounds[], so every diff printed "(no patch attached)" |
Re-run the audit by diffing both surfaces:
# every lexicon each side calls
grep -rhoE '"(sh\.tangled|com\.atproto)[a-zA-Z.#]+"' <tg> --include='*.go' | tr -d '"' | sort -u
grep -rhoE '"(sh\.tangled|com\.atproto)[a-zA-Z.#]+"' crates --include='*.rs' | tr -d '"' | sort -u
Known differences that are deliberate, as of the last audit:
com.atproto.sync.getBlobis used, but built into a URL rather than named as a literal, so the grep above will not see it. Do not "re-add" it.sh.tangled.ci.trigger#pushand#pullRequestare match arms in tg for display. Triggers are kept as raw JSON here, so an unknown trigger kind cannot fail a response.com.atproto.server.getSessionis unused:auth statusreports the stored session without a round trip.sh.tangled.knotrecords are unused: onlyknot migrateexists, not a listing of registered knots.
Contributing #
Contributions are welcome! Please feel free to submit issues or pull requests.
License #
MIT OR Apache-2.0