- Rust 100%
- Nix <1%
- Shell <1%
tanghole #
Warning
Both tangled and this cli are in an experimental phase. Use at your own discretion.
th is a command-line client for Tangled, a decentralized git collaboration platform built on the AT Protocol.
This cli is meant for both humans & agents.
tanghole is the maintained continuation of tangled-cli by dzejkop and its contributors (the tang command), which stopped following Tangled before its move to org.tangled.* records. It keeps tangled-cli's history, licence and configuration: a session made with th auth login and ~/.config/tangled carry over to th.
Installation #
crates.io #
cargo install tanghole
Nix #
With Nix flakes enabled, run it directly from Tangled without cloning:
nix run 'git+https://tangled.org/7778777.online/tanghole#default' -- --help
To open a shell with th available:
nix shell 'git+https://tangled.org/7778777.online/tanghole#default'
Build from Source #
git clone https://tangled.org/7778777.online/tanghole
cd tanghole
cargo install --locked --path crates/tanghole
Getting started #
-
Login to Tangled:
th auth login -
List your repositories:
th repo list -
Create a new repository:
th repo create myproject --description "My cool project" -
Clone a repository:
th repo clone username/reponame
Workspace Structure #
crates/tanghole- CLI binary with clap-based argument parsingcrates/tanghole-config- Configuration and session management (keyring-backed)crates/tanghole-api- XRPC client wrapper for AT Protocol and Tangled APIs
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://api.tangled.org)TANGLED_DEFAULT_KNOT- Override the default knot for new repos (default:knot1.tangled.sh)TANGLED_WEB_BASE- The web front end printed links point at (default:https://tangled.org)TANGLED_PLC_URL- Override the PLC directory DID documents are read from (default:https://plc.directory)
How th talks to Tangled #
Tangled keeps a repository in two halves that must agree: an
org.tangled.repo.declaration on the owner's PDS (record key = the
lowercased name) naming the repository's own DID, and an
org.tangled.repo.manifest in that DID's account on its knot. Issues and
pulls (tickets), their comments and patches, and release artifacts live in
the repository account too. th writes there by posting
com.atproto.repo.* to the knot with a service-auth token minted on your
PDS for the repository's DID, and then writes an
org.tangled.graph.attestation on your PDS claiming the write, as the web
does. Listings (issues, pulls, comments, a pull's revisions) are read from
Tangled's indexer, TANGLED_API_BASE.
Examples #
Working with Repositories #
# Create a repository on the default knot (the knot mints its DID)
th repo create myproject --description "My cool project" --default-branch main
# Fork: the knot clones the source; or import from any clone URL
th repo create myfork --source someone.example/project
th repo create mirror --source https://github.com/owner/project
# List your repositories: STATUS is `listed`, `unlisted: ...` (declaration
# and manifest disagree, so tangled.org 404s it) or `legacy: ...` (only an
# old sh.tangled.repo record)
th repo list
# Delete (asks first; --force to skip the question, required when it can't ask)
th repo delete myproject --force
# Mark a repository as a fork of another (edits the manifest on the knot)
th repo set-source myfork someone.example/project
Release artifacts #
Artifacts are files on an annotated tag, stored in the repository's account on its knot (at most 50 MiB each). Run these inside a clone that has the tag:
th repo artifact upload --repo myproject --tag v1.0.0 dist/*.tar.zst SHA256SUMS
th repo artifact upload --repo myproject --tag v1.0.0 --skip-existing dist/*
th repo artifact list --repo myproject
th repo artifact delete --repo myproject --tag v1.0.0 old.tar.zst
Uploading a name the tag already has is refused (nothing is uploaded)
unless --skip-existing is given.
Working with Issues #
An issue is an org.tangled.track.ticket in the repository's account on its
knot; the knot numbers it. Commands take the number (in --repo, or the
repository of the current checkout) or the ticket's AT-URI.
# Create an issue (labels must be defined on the repository)
th issue create --repo myrepo --title "Bug: Fix login" --body "Description here" --label bug
# List issues (newest first), optionally by state, author, label or assignee
th issue list --repo myrepo --state open
# Show an issue with its comments
th issue show 12 --repo myrepo
# Comment, reply to a comment, close or reopen
th issue comment 12 --body "I'll fix this"
th issue comment 12 --body "Agreed" --reply-to 3mabcdefgh2k
th issue close 12
th issue reopen 12
th issue edit 12 --title "Login fails on Safari" --state completed
Only the issue's author or a maintainer can change its state; the knot refuses anyone else.
Working with Pulls #
A pull is a ticket with a target branch, plus immutable revisions
(org.tangled.review.patch) naming a base and head commit. The knot must be
able to reach the head: push the branch first, to the target repository or
to your fork of it.
# Propose the current branch for the default branch of the checkout's repo
git push origin my-feature
th pull create --title "Add new feature"
# From a fork's checkout, propose to the repository it was forked from
th pull create --target source --base main --head my-feature
# List, show (with --diff for the patch, --checks for its CI runs)
th pull list --repo myrepo --state open
th pull show 41 --repo myrepo --diff
# Review: a comment on the pull about its latest commit
th pull review 41 --approve --comment "LGTM!"
# Merge (rebases onto the target branch on Tangled's mirror and pushes it),
# or close without merging
th pull merge 41
th pull close 41
CI on a spindle #
Pipelines run on the spindle the repository's manifest names
(th spindle config --enable sets Tangled's).
th spindle list --repo myrepo
th spindle run --repo myrepo --branch main --wait
th spindle logs 3mpipelineid --repo myrepo
th spindle secret add --repo myrepo --key DEPLOY_TOKEN --value @~/token
th knot migrate refuses: moving an org.tangled.* repository between
knots is a handover only knot admins can run.
Contributing #
Contributions are welcome! Please feel free to submit issues or pulls.
License #
MIT OR Apache-2.0