# Tangle Hub Reference

## Response Shapes

The CLI `--json` flag prints raw response data. The SDK internally uses envelopes (`{ success: true, data: ... }` / `{ success: false, error: ... }`), but the CLI unwraps the envelope and prints only the `data` or formats the `error`.

**Success output:** raw data object directly (no envelope wrapper).
**Error output:** `{ error: { code, message, status?, details? } }`.

### Status

```bash
tangle hub status --json
```

```json
{
  "principal": {
    "kind": "user_session",
    "userId": "usr_xxx",
    "apiKeyId": "key_xxx",
    "sandboxId": null
  },
  "connections": {
    "connectedProviderCount": 2,
    "unhealthyProviderCount": 0
  }
}
```

`kind` values: `user_session`, `api_key`, `sandbox_runtime`.

### Connections

```bash
tangle hub connections --json
```

```json
{
  "connections": [
    {
      "id": "hubconn_github_a1",
      "providerId": "github",
      "displayName": "GitHub",
      "accountDisplay": "octocat",
      "scopes": ["repo", "user:email"],
      "status": "active",
      "health": "healthy",
      "createdAt": "2026-01-15T10:00:00Z",
      "updatedAt": "2026-01-15T10:00:00Z",
      "lastUsedAt": "2026-06-10T08:00:00Z"
    }
  ]
}
```

Connection `status`: `active`, `revoked`, `unhealthy`, `reconnect_required`.

Connection `health`: `unknown`, `healthy`, `unhealthy`, `rate_limited`.

#### Connection references

Anywhere a command takes a connection (`--connection`, `connections revoke`,
`agent --connection`), you may pass a raw connection id (`hubconn_...`) or a
human reference instead:

- `<provider>`, for example `github`, resolves when you hold exactly one connection
  for that provider.
- `<provider>:<account>`, for example `gmail:alice@example.com`, disambiguates when
  you hold several connections for one provider (matches `accountDisplay` or
  `displayName`).

A reference resolves against `tangle hub connections`; revoked connections are
skipped. If it matches no connection, or more than one, the CLI fails loud and
lists the candidates so you can pass an id or `provider:account`. Raw ids never
contact the hub for resolution. The `agent --connection` head is followed by
`:capabilities`, so it accepts a provider or an id but not `provider:account`;
use an id when a provider is ambiguous there.

### OAuth Connect

```bash
tangle hub connect github --json
```

```json
{
  "provider": "github",
  "redirectUrl": "https://github.com/login/oauth/authorize?client_id=...&scope=repo&state=...",
  "expiresAt": "2026-06-10T12:30:00Z",
  "scopes": ["repo", "user:email"],
  "cli": true
}
```

The `state` field is redacted from `--json` output (CSRF protection). The CLI prints the raw redirect URL directly.

### Tool Sources

```bash
tangle hub tools sources --json
```

```json
{
  "sources": [
    {
      "sourceId": "github",
      "providerId": "github",
      "displayName": "GitHub",
      "toolCount": 47,
      "connectionStatus": "connected",
      "health": "healthy",
      "configured": true
    }
  ]
}
```

Source `connectionStatus`: `connected`, `missing`, `unknown`.

Source `health`: `healthy`, `unhealthy`, `rate_limited`, `unknown`.

### Tool Search

```bash
tangle hub tools search "github issues" --provider github --json
```

```json
{
  "tools": [
    {
      "path": "github.issues.search",
      "providerId": "github",
      "title": "Search issues and pull requests",
      "description": "Search GitHub issues and pull requests with a query",
      "connectionRequired": true,
      "connectionStatus": "connected",
      "requiredConnectionProviderId": "github",
      "policyState": "ask"
    }
  ]
}
```

Tool `policyState`: `allow`, `ask`, `deny`, `unknown`.

### Tool Describe

```bash
tangle hub tools describe github.issues.search --json
```

```json
{
  "tool": {
    "path": "github.issues.search",
    "providerId": "github",
    "title": "Search issues and pull requests",
    "description": "Search GitHub issues and pull requests with a query",
    "connectionRequired": true,
    "connectionStatus": "connected",
    "requiredConnectionProviderId": "github",
    "policyState": "ask",
    "inputSchema": {
      "type": "object",
      "required": ["q"],
      "properties": {
        "q": { "type": "string" },
        "sort": { "type": "string", "enum": ["comments", "created", "updated"] },
        "order": { "type": "string", "enum": ["asc", "desc"] }
      }
    },
    "outputSchema": {
      "type": "object",
      "properties": {
        "total_count": { "type": "integer" },
        "items": { "type": "array", "items": { "$ref": "#/components/schemas/Issue" } }
      }
    }
  }
}
```

### Tool Call / Exec

```bash
tangle hub call github issues search '{"q":"repo:tangle-network/agent-dev-container is:issue"}'
tangle hub exec github.issues.search '{"q":"repo:tangle-network/agent-dev-container is:issue"}'
```

```json
{
  "result": {
    "total_count": 1,
    "items": [
      {
        "number": 42,
        "title": "Fix auth middleware",
        "state": "open",
        "createdAt": "2026-06-01T10:00:00Z"
      }
    ]
  }
}
```

The `result` shape depends on the tool. Always inspect the `outputSchema` first.

### Approvals

```bash
tangle hub approvals list --json
```

```json
{
  "approvals": [
    {
      "id": "app_xxx",
      "connectionId": "hubconn_github_a1",
      "providerId": "github",
      "actionPath": "github.issues.create",
      "inputHash": "sha256:...",
      "requesterPrincipal": { "userId": "usr_xxx", "kind": "api_key" },
      "status": "pending",
      "requestedAt": "2026-06-10T08:00:00Z",
      "expiresAt": "2026-06-10T09:00:00Z",
      "resolvedAt": null
    }
  ]
}
```

Approval `status`: `pending`, `approved`, `denied`, `expired`, `consumed`.

### Approve / Deny

```bash
tangle hub approvals approve app_xxx --json
tangle hub approvals deny app_xxx --json
```

```json
{
  "approval": {
    "id": "app_xxx",
    "status": "approved",
    "connectionId": "hubconn_github_a1",
    "actionPath": "github.issues.create"
  },
  "capabilityToken": {
    "tokenId": "tok_xxx",
    "expiresAt": "2026-06-10T08:30:00Z"
  }
}
```

`capabilityToken` is present only on approve. The actual token value is redacted from `--json` output.

### Permissions

```bash
tangle hub permissions list --connection hubconn_github_a1 --json
```

```json
{
  "policies": [
    {
      "id": "pol_xxx",
      "connectionId": "hubconn_github_a1",
      "providerId": "github",
      "actionPath": "github.issues.create",
      "decision": "ask",
      "createdAt": "2026-06-01T00:00:00Z",
      "updatedAt": "2026-06-10T00:00:00Z"
    }
  ]
}
```

`decision` values: `allow`, `ask`, `deny`.

### Permission Set

```bash
tangle hub permissions set --connection hubconn_github_a1 --action github.issues.create --decision allow --json
```

```json
{
  "policy": {
    "id": "pol_xxx",
    "connectionId": "hubconn_github_a1",
    "providerId": "github",
    "actionPath": "github.issues.create",
    "decision": "allow",
    "createdAt": "2026-06-01T00:00:00Z",
    "updatedAt": "2026-06-10T00:00:00Z"
  }
}
```

### Granting connections to an agent

`tangle agent prompt` exposes granted hub connections to the agent as MCP tools
with `--connection <spec>` (repeatable). Three modes, from least to most
privilege:

The spec head is a connection id or a provider name (see
[Connection references](#connection-references)).

```bash
# Least privilege (recommended): the agent sees exactly these tool paths.
tangle agent prompt sbx_123 "triage issues" \
  --connection github:github.issues.search,github.issues.create

# All capabilities of one connection (by id when a provider is ambiguous).
tangle agent prompt sbx_123 "triage issues" --connection hubconn_github_a1:*

# All capabilities of every connected provider (broadest).
tangle agent prompt sbx_123 "do the thing" --connection '*:*'
```

A grant controls what the agent can **see**. Each call is still policy-gated
(`allow`/`ask`/`deny`); by default reads are allowed and writes/destructive
actions prompt for approval.

### `--allow-writes`

Pre-approve every **write** action of each granted connection so an autonomous
run can write without per-action prompts. Reads are already allowed; destructive
actions still prompt. The grant is persistent and scoped to the named
connections only.

```bash
tangle agent prompt sbx_123 "file the weekly report" \
  --connection github:* --allow-writes
```

Revert the bulk grant at any time.
It deletes only the rows `--allow-writes`
created, leaving manual `permissions set` decisions intact:

```bash
tangle hub permissions revert-writes --connection github
```

> `--allow-writes` needs a named connection (id or provider); the `*:*`
> wildcard can't be bulk-granted. Pass `--no-hub-key` (or set
> `TANGLE_SKIP_HUB_KEY=1`) to skip auto-minting a platform Hub key and use your
> stored credential as-is.

## Error Format

```bash
# Any failing hub command with --json
tangle hub tools sources --json  # when not authenticated
```

```json
{
  "error": {
    "code": "HUB_UNAUTHENTICATED",
    "message": "Authentication required for Hub endpoints",
    "status": 401
  }
}
```

Error fields:
- `code`: Hub error code string
- `message`: Human-readable description
- `status`: HTTP status code (optional)
- `details`: Additional context (optional)

## Error Codes

| Code | When it occurs | Recovery |
|------|----------------|----------|
| `HUB_UNAUTHENTICATED` | Missing or invalid API key | Check `TANGLE_API_KEY` |
| `HUB_FORBIDDEN` | Valid auth but no permission | Check connection or team membership |
| `HUB_INVALID_INPUT` | JSON schema violation | Check `inputSchema` with `tools describe` |
| `HUB_PROVIDER_MISSING` | Provider not configured | `tangle hub connect <provider>` |
| `HUB_CONNECTION_MISSING` | No connection for this provider | `tangle hub connect <provider>` |
| `HUB_CONNECTION_REVOKED` | Connection was revoked | Reconnect via `tangle hub connect` |
| `HUB_TOKEN_EXPIRED` | Capability token expired | Re-run with `--approve` or mint new token |
| `HUB_TOKEN_REPLAYED` | Token already consumed | Re-run with `--approve` |
| `HUB_TOKEN_REVOKED` | Token explicitly revoked | Re-run with `--approve` |
| `HUB_TOKEN_ACTION_MISMATCH` | Token for different action | Use `--approve` with correct action |
| `HUB_POLICY_DENIED` | Permission set to `deny` | Change policy via `permissions set` |
| `HUB_APPROVAL_REQUIRED` | Policy is `ask` and first use | Use `--approve` or `approvals approve` |
| `HUB_EXECUTOR_FAILURE` | Hub executor error | Retry; check tool health |
| `HUB_PROVIDER_FAILURE` | Provider API error | Check provider status |
| `HUB_NOT_FOUND` | Tool or resource not found | Check path spelling |
| `HUB_NOT_IMPLEMENTED` | Route not yet implemented | Use a different endpoint |

## Workflow Examples

### Connect → Call → Approve

```bash
# 1. Connect
tangle hub connect github
# (follow browser flow)

# 2. Verify
tangle hub status --json

# 3. Discover
tangle hub tools sources --json
tangle hub tools search "issues" --provider github --json
tangle hub tools describe github.issues.search --json

# 4. Call with auto-approve
tangle hub exec github.issues.search '{"q":"repo:tangle-network/agent-dev-container is:issue"}' --approve

# 5. Set permanent policy
tangle hub permissions set --connection hubconn_github_a1 --action github.issues.search --decision allow
```

### Batch Approvals

```bash
# List all pending
tangle hub approvals list --json | jq '.approvals[] | .id'

# Bulk approve
for id in $(tangle hub approvals list --json | jq -r '.approvals[].id'); do
  tangle hub approvals approve "$id"
done
```

### Policy Audit

```bash
# Show all policies for one connection
tangle hub permissions list --connection hubconn_github_a1 --json

# Set all read actions to allow, write actions to ask
tangle hub permissions set --connection hubconn_github_a1 --action github.issues.search --decision allow
tangle hub permissions set --connection hubconn_github_a1 --action github.issues.create --decision ask
```

## GitHub App Primitives

```bash
# Mint a repo-scoped token (requires GitHub App installation)
tangle hub github-app mint-installation-token --repo-url https://github.com/owner/repo

# Check if repo is installed
tangle hub github-app is-repo-installed --owner owner --repo repo

# List installations
tangle hub github-app installations

# List repos for an installation
tangle hub github-app repos --installation-id 123456
```

## Token Management

```bash
# List minted capability tokens
tangle hub tokens list --json

# List including expired
tangle hub tokens list --include-expired --json

# Revoke a token
tangle hub tokens revoke tok_xxx --json
```
