···11# tang
2233-`tang` is a work-in-progress command-line client for Tangled.
33+`tang` is a command-line client for [Tangled](https://tangled.org/).
44+It is designed for day-to-day repository work from a terminal: checking your
55+Tangled identity, managing SSH keys, finding the current repository, listing and
66+creating issues, and working with pull requests.
77+88+The tool talks to Tangled through its AT Protocol data model:
99+1010+- Authentication is performed against the user's PDS.
1111+- Issues, pull requests, comments, status records, and SSH keys are stored as
1212+ ATProto records.
1313+- Repository and pull request operations use the Tangled AppView, Constellation,
1414+ and knot APIs as needed.
1515+1616+## Status
1717+1818+This project is usable for the implemented workflows, but still early. The
1919+current command set covers:
2020+2121+- `auth`: login, logout, token refresh, token inspection, auth status.
2222+- `status`: combined auth, repository, and service status.
2323+- `config`: local configuration for knot, AppView, Constellation, and preferred
2424+ git remote.
2525+- `ssh-key`: list, add, and delete Tangled SSH public keys.
2626+- `repo`: view, list, create, and clone repositories.
2727+- `issue`: list, create, view, edit, comment, close, and reopen issues.
2828+- `pr`: list, create, view, diff, comment, checkout, close, reopen, and merge
2929+ pull requests.
3030+- `browse`: open Tangled pages from the current repository context.
3131+- `completion`: generate shell completions.
3232+3333+Some Tangled server-side behavior is eventually consistent. After creating,
3434+closing, reopening, or commenting on records, AppView and Constellation results
3535+may take a short time to reflect the latest state.
3636+3737+## Installation
3838+3939+Build a local binary:
4040+4141+```sh
4242+make build
4343+./bin/tang --help
4444+```
4545+4646+Install into your Go binary path:
4747+4848+```sh
4949+make install
5050+tang --help
5151+```
5252+5353+The module currently targets Go 1.25.
5454+5555+## First-Time Setup
5656+5757+Log in with a Tangled handle and app password:
5858+5959+```sh
6060+tang auth login --handle alice.example
6161+```
6262+6363+The command prompts for the app password. Session credentials are stored through
6464+the operating system keyring when available. The PDS URL is resolved from the
6565+handle's DID document; `pds.url` is intentionally not a persistent config key.
6666+6767+Check the session:
6868+6969+```sh
7070+tang auth status
7171+tang auth refresh
7272+tang auth token --json
7373+```
7474+7575+Manage SSH keys:
7676+7777+```sh
7878+tang ssh-key list
7979+tang ssh-key add ~/.ssh/id_ed25519.pub
8080+tang ssh-key delete <key-rkey>
8181+```
8282+8383+Use `ssh-key list --json` when you need stable record identifiers for deletion
8484+or automation.
8585+8686+## Repository Context
8787+8888+Most repository-scoped commands can infer the target repository from the current
8989+git worktree. `tang` scans git remotes and selects a Tangled remote using this
9090+order:
9191+9292+1. The configured preferred remote from `tang config set remote <name>`.
9393+2. `origin`, when it is a Tangled remote.
9494+3. The first Tangled remote found.
9595+9696+Supported repository selectors include:
9797+9898+```sh
9999+tang status
100100+tang repo view
101101+tang issue list
102102+tang pr list
103103+```
104104+105105+You can override the inferred repository with `-R`:
106106+107107+```sh
108108+tang issue list -R onev.cat/tang
109109+tang pr view 1 -R tangled.org/core
110110+```
111111+112112+The selector format is `[HOST/]OWNER/REPO`. If no host is provided, configured
113113+knot hosts are used.
114114+115115+## Core Workflows
116116+117117+### Inspect Your Environment
118118+119119+```sh
120120+tang status
121121+tang status --section auth
122122+tang status --section repo
123123+tang config list
124124+```
125125+126126+Use JSON output for scripts:
127127+128128+```sh
129129+tang status --json
130130+tang status --json=auth,repository
131131+tang repo view --json=name,knot,uri
132132+```
133133+134134+`--json` without a value prints all fields. `--json=a,b,c` prints only selected
135135+fields.
136136+137137+### Work With Repositories
138138+139139+View the current repository:
140140+141141+```sh
142142+tang repo view
143143+```
144144+145145+List repositories for an owner:
146146+147147+```sh
148148+tang repo list onev.cat
149149+```
150150+151151+Clone a repository:
152152+153153+```sh
154154+tang repo clone onev.cat/tang-playground
155155+tang repo clone onev.cat/tang-playground ./playground
156156+```
157157+158158+Create a repository:
159159+160160+```sh
161161+tang repo create my-tool --description "A small Tangled tool" --knot knot1.tangled.sh
162162+```
163163+164164+Repository creation depends on the selected knot. If the default AppView does
165165+not expose a create-capable route, pass an explicit `--knot`.
166166+167167+### Work With Issues
168168+169169+List issues:
170170+171171+```sh
172172+tang issue list
173173+tang issue list --state all
174174+tang issue list --state closed --limit 20
175175+```
176176+177177+Create an issue:
178178+179179+```sh
180180+tang issue create "Fix repository context detection" --body "Remote parsing misses push URLs."
181181+```
182182+183183+Read a body from a file or stdin:
418455-The project is not yet usable for day-to-day workflows. The initial milestones build toward auth, repository, issue, pull request, SSH key, status, config, browse, and completion commands.
185185+```sh
186186+tang issue create "Document release process" --body-file ./issue.md
187187+printf 'Body from stdin\n' | tang issue create "CLI polish" --body-file -
188188+```
189189+190190+View, comment, edit, and change state:
191191+192192+```sh
193193+tang issue view 1
194194+tang issue view 1 --web
195195+tang issue comment 1 --body "Confirmed on main."
196196+tang issue edit 1 --title "Fix remote context detection"
197197+tang issue close 1
198198+tang issue reopen 1
199199+```
200200+201201+Issue arguments may be a displayed number such as `1` or `#1`, a record rkey, or
202202+a full AT URI.
203203+204204+### Work With Pull Requests
205205+206206+List and inspect pull requests:
207207+208208+```sh
209209+tang pr list
210210+tang pr list --state all
211211+tang pr view 1
212212+tang pr view 1 --web
213213+tang pr diff 1
214214+```
215215+216216+Create a pull request from a pushed branch:
217217+218218+```sh
219219+git push origin my-branch
220220+tang pr create --base main --head my-branch --title "Add repository docs" --body-file ./pr.md
221221+```
222222+223223+When the patch contains a mail-style subject, `--fill` can derive the title:
224224+225225+```sh
226226+tang pr create --base main --head my-branch --fill
227227+```
228228+229229+Review and update a pull request:
230230+231231+```sh
232232+tang pr comment 1 --body "Looks good after the latest patch."
233233+tang pr checkout 1
234234+tang pr close 1
235235+tang pr reopen 1
236236+```
237237+238238+Merge a pull request:
239239+240240+```sh
241241+tang pr merge 1 --subject "Merge pull request #1"
242242+```
243243+244244+`pr merge` applies the pull request patch locally, commits it, and records the
245245+pull request as merged on Tangled. Review the worktree before and after merging,
246246+especially when the pull request contains a large patch.
247247+248248+Pull request arguments may be a displayed number such as `1` or `#1`, a record
249249+rkey, or a full AT URI.
250250+251251+### Open Tangled In A Browser
252252+253253+Open the current repository page:
254254+255255+```sh
256256+tang browse
257257+```
258258+259259+Open an issue:
260260+261261+```sh
262262+tang browse issue 1
263263+```
264264+265265+### Configure Services
266266+267267+Configuration is stored under the user config directory as `tang/config.toml`
268268+for the current platform.
269269+270270+Common settings:
271271+272272+```sh
273273+tang config list
274274+tang config get knot.hosts
275275+tang config set knot.hosts tangled.org,knot1.tangled.sh
276276+tang config set appview.url https://tangled.org
277277+tang config set constellation.url https://constellation.microcosm.blue
278278+tang config set remote origin
279279+```
280280+281281+`TANG_CONSTELLATION_URL` overrides `constellation.url` at runtime. This is useful
282282+for testing against a local or staging Constellation instance.
283283+284284+## Global Flags
285285+286286+All commands support:
287287+288288+```text
289289+--json[=fields] Output JSON, optionally filtered by comma-separated fields.
290290+--pds URL Override PDS URL for auth and testing.
291291+-R, --repo REPO Select another repository using [HOST/]OWNER/REPO.
292292+```
293293+294294+Use `--pds` for tests and diagnostics. Normal login and write workflows should
295295+let `tang` resolve the PDS from the active identity.
296296+297297+## Shell Completion
298298+299299+Generate shell completion scripts:
300300+301301+```sh
302302+tang completion zsh
303303+tang completion bash
304304+tang completion fish
305305+tang completion powershell
306306+```
63077308## Development
8309310310+Useful commands:
311311+9312```sh
10313make test
314314+make lint
11315make build
12316./bin/tang --help
13317```
318318+319319+The main implementation areas are:
320320+321321+- `cmd/tang`: binary entry point.
322322+- `internal/cli`: Cobra command wiring and user-facing behavior.
323323+- `internal/auth`: session and keyring handling.
324324+- `internal/config`: TOML config loading and supported keys.
325325+- `internal/git`: git remote parsing.
326326+- `internal/repo`: repository context resolution.
327327+- `internal/tangled`: Tangled AppView, PDS, knot, issue, repository, and pull
328328+ request clients.
329329+- `internal/constellation`: Constellation API client.
330330+331331+Before changing behavior, prefer adding focused tests near the package that owns
332332+the logic. For command behavior, use `internal/cli` tests. For record parsing,
333333+resolution, and API mapping, use `internal/tangled`, `internal/git`, or
334334+`internal/repo` tests.
335335+336336+## Known Limitations
337337+338338+- Tangled AppView and Constellation indexing may lag behind successful PDS
339339+ writes.
340340+- Some older pull request records do not contain patch rounds, so `pr diff` and
341341+ `pr checkout` cannot operate on them.
342342+- `repo create` requires a create-capable knot. Pass `--knot` when the default
343343+ service route is not sufficient.
344344+- `pr merge` is intentionally local-git based. It applies the patch and creates
345345+ a commit in the current worktree, so the caller remains responsible for
346346+ reviewing and pushing the result.