···16161717### Git SSH Key Management
18181919+#### Lexicon Details
2020+2121+**`sh.tangled.publicKey` Record Schema** (from `core/lexicons/publicKey.json`):
2222+```json
2323+{
2424+ "lexicon": 1,
2525+ "id": "sh.tangled.publicKey",
2626+ "key": "tid",
2727+ "record": {
2828+ "required": ["key", "name", "createdAt"],
2929+ "properties": {
3030+ "key": {
3131+ "type": "string",
3232+ "maxLength": 4096,
3333+ "description": "public key contents"
3434+ },
3535+ "name": {
3636+ "type": "string",
3737+ "description": "human-readable name for this key"
3838+ },
3939+ "createdAt": {
4040+ "type": "string",
4141+ "format": "datetime",
4242+ "description": "key upload timestamp"
4343+ }
4444+ }
4545+ }
4646+}
4747+```
4848+4949+**`sh.tangled.knot.listKeys` Query** (from `core/lexicons/knot/listKeys.json`):
5050+- Query endpoint for listing public keys stored on the knot server
5151+- Returns: Array of `{ did, key, createdAt }`
5252+- Supports pagination with `limit` and `cursor` parameters
5353+5454+#### Implementation Approach
5555+1956* **`tangled ssh-key add <public-key-path>`**:
2020- * **Feasible (using generic ATProto record creation).** The `core/lexicons/publicKey.json` defines the `sh.tangled.publicKey` record type. To add a user's global SSH public key, the CLI would use the generic ATProto `com.atproto.repo.createRecord` procedure. The `collection` parameter would be set to `sh.tangled.publicKey`, and the public key content (`key`) and a human-readable name (`name`) would be provided as the record data.
5757+ * **Feasible (using generic ATProto record creation).**
5858+ * Uses `AtpAgent.com.atproto.repo.createRecord()` with:
5959+ - `collection: "sh.tangled.publicKey"`
6060+ - `record: { key, name, createdAt }`
6161+ * The record will be stored on the user's PDS (Personal Data Server)
6262+ * The CLI reads the public key file, validates the format, and creates the record
6363+2164* **`tangled ssh-key verify`**:
2265 * **Feasible.** This command can be implemented by:
2323- 1. Executing `ssh -T git@tangled.org` to capture the authenticated user's DID from the server response.
2424- 2. Using the `sh.tangled.knot.listKeys` query (defined in `core/lexicons/knot/listKeys.json`) to fetch a list of public keys known to the knot server. This query returns objects that include the `did` associated with each key.
2525- 3. Comparing the DID obtained from the SSH output with the DIDs returned by `listKeys` to confirm the key's association.
2626- 4. Resolving the DID to a human-readable Bluesky handle using the standard AT Protocol `com.atproto.identity.resolveHandle` procedure (part of `@atproto/api`).
6666+ 1. Executing `ssh -T git@tangled.org` to capture the authenticated user's DID from the server response
6767+ 2. Parsing the DID from the SSH output
6868+ 3. Resolving the DID to a human-readable Bluesky handle using `com.atproto.identity.resolveHandle`
6969+ * Note: The `sh.tangled.knot.listKeys` query is available but may require knot server access
7070+7171+#### TypeScript/JavaScript Tools
7272+7373+- **`@atproto/api`**: Main SDK for AT Protocol operations
7474+ - `AtpAgent` class handles authentication and API calls
7575+ - Built-in methods for `com.atproto.repo.createRecord`, `getRecord`, `listRecords`
7676+7777+- **`@atproto/lexicon`**: Schema validation library
7878+ - `Lexicons` class for loading and validating custom schemas
7979+ - Provides `assertValidRecord()` for validating record data against lexicons
8080+8181+- **Direct Record Creation**: No code generation needed
8282+ ```typescript
8383+ await agent.com.atproto.repo.createRecord({
8484+ repo: agent.session.did,
8585+ collection: 'sh.tangled.publicKey',
8686+ record: {
8787+ key: publicKeyContent,
8888+ name: keyName,
8989+ createdAt: new Date().toISOString()
9090+ }
9191+ })
9292+ ```
27932894### Repository Management
2995
+12-10
README.md
···35353636## Tech Stack (TypeScript)
37373838-| Component | Library | Purpose |
3939-| :---------------- | :-------------------- | :------------------------------------------------------------ |
4040-| **Framework** | **commander** | Routing (tangled repo create). |
4141-| **API Client** | **@atproto/api** | Official XRPC client & session management. |
4242-| **Git Context** | **git-url-parse** | **New:** Parses remote URLs to extract the Tangled DID/NSID. |
4343-| **Git Ops** | **simple-git** | Wraps local git operations safely. |
4444-| **Validation** | **zod** | Validates inputs & generates schemas for LLMs. |
4545-| **Interactivity** | **@inquirer/prompts** | Modern prompts for humans. |
4646-| **Formatting** | **cli-table3** | **New:** For gh-style pretty tables in Human Mode. |
4747-| **OS Keychain** | **keytar** | **New:** To securely store session tokens in the OS keychain. |
3838+| Component | Library | Purpose |
3939+| :---------------- | :---------------------- | :--------------------------------------------------------------------------------------------- |
4040+| **Framework** | **commander** | CLI routing and command parsing (e.g., `tangled repo create`). |
4141+| **API Client** | **@atproto/api** | Official AT Protocol XRPC client, session management, and record operations. |
4242+| **Lexicon Tools** | **@atproto/lexicon** | Schema validation for custom Tangled.org lexicons (e.g., `sh.tangled.publicKey`). |
4343+| **Git Context** | **git-url-parse** | Parses remote URLs to extract the Tangled DID/NSID from `.git/config`. |
4444+| **Git Ops** | **simple-git** | Wraps local git operations safely. |
4545+| **Validation** | **zod** | Input validation and schema generation for LLMs. |
4646+| **Interactivity** | **@inquirer/prompts** | Modern, user-friendly prompts for interactive flows. |
4747+| **Formatting** | **cli-table3** | Pretty tables for "Human Mode" output (following gh CLI patterns). |
4848+| **OS Keychain** | **@napi-rs/keyring** | Cross-platform secure storage for AT Protocol session tokens (macOS, Windows, Linux). |
4949+| **TypeScript** | **tsx** | Fast TypeScript execution for development and testing. |
48504951## Agent Integration (The "LLM Friendly" Layer)
5052