Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: test

on:
push:
branches: [main]
pull_request:

# This workflow intentionally checks out live Interchange until mediated
# credentials ship in a released package; it is integration CI, not release CI.

jobs:
typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
path: x-tools
- uses: actions/checkout@v4
with:
repository: corbitsdev/interchange
path: interchange
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.14
- name: Install Interchange (for @intx/* links)
working-directory: interchange
run: bun install --frozen-lockfile
- name: Install x-tools
working-directory: x-tools
run: bun install --frozen-lockfile
- name: Link Interchange packages
working-directory: x-tools
run: bun run link:intx
- working-directory: x-tools
run: bun run typecheck

test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
path: x-tools
- uses: actions/checkout@v4
with:
repository: corbitsdev/interchange
path: interchange
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.14
- working-directory: interchange
run: bun install --frozen-lockfile
- working-directory: x-tools
run: bun install --frozen-lockfile
- working-directory: x-tools
run: bun run link:intx
- working-directory: x-tools
run: bun run test

build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
path: x-tools
- uses: actions/checkout@v4
with:
repository: corbitsdev/interchange
path: interchange
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.14
- working-directory: interchange
run: bun install --frozen-lockfile
- working-directory: x-tools
run: bun install --frozen-lockfile
- working-directory: x-tools
run: bun run link:intx
- working-directory: x-tools
run: bun run build
9 changes: 8 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,25 @@ Instructions for AI agents working in this repository.

## Overview

**Corbits Tools for X** — tooling for X (Twitter).
**Corbits Tools for X** (`@corbits/x-tools`) — X API client and Interchange
tools (credential handle `x-api`). See ARCHITECTURE.md.

## Conventions

- **Runtime:** Bun + TypeScript, ES modules only.
- Touch only code related to the task.
- Comment *why*, never *what*.
- No emojis in code or docs.
- Package never reads `process.env` — hosts pass options explicitly.
- Tool names match X MCP / xmcp names as-is.
- Field defaults mirror xurl shortcuts unless the caller overrides.

## Build & Validation

```bash
bun install
bun run link:intx
bun run typecheck
bun test
bun run build
```
65 changes: 65 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Architecture

## What this package is

`@corbits/x-tools` is an X API client plus an Interchange tool package. Tools
authenticate through Interchange's **mediated credential** rail — the secret
never appears on the tool options API.

## Interchange credentials

Declared in `package.json`:

```json
"interchange": {
"tools": "./dist/sidecar-bundle.js",
"credentials": [{ "handle": "x-api" }]
}
```

At runtime the sidecar factory (`src/sidecar-bundle.ts`):

1. Receives `env.capabilities` from the host (`requires: ["capabilities"]`)
2. Builds a tool runner with the capabilities
3. On the first tool call, resolves `credentials` → handle `x-api` → http
mediated credential and caches the client
4. Uses `createXClient({ fetchImpl: mediated.fetch })` — Bearer is injected by
Interchange per request, pinned to the provider origin (`https://api.x.com`)

Agent definitions bind the handle:

```ts
credentialBindings: [{
package: "@corbits/x-tools",
handle: "x-api",
provider: "x", // tenant provider whose origin is https://api.x.com
locator: "tenant",
}]
```

See Interchange `docs/CREDENTIALS.md` and the credential-probe e2e fixture.

The client accepts only an injected `fetchImpl`; production passes the mediated
credential's fetch and tests provide a stub.

## Layout

```
src/
client/ # createXClient, XAPIError
tools/ # definitions, domain handlers, createXTools
sidecar-bundle.ts # defineTool export for the Interchange loader
index.ts
```

Depends on a sibling `../interchange` checkout. Run `bun run link:intx` to
symlink its packages so we track live `intx-src` — not the stale npm `0.2.2`
cut.
## Tool delivery plan (v1)

1. Users → 2. Posts → 3. Search → 4. Bookmarks → 5. Media → 6. News / Trends

## Phase 2 (deferred)

Lists, DMs, Spaces, Communities, Community Notes, Articles, XChat, compliance /
Account Activity webhooks.
28 changes: 28 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Contributing

A small, deliberately boring codebase: strict TypeScript, no magic.

Setup and commands are in the [README](./README.md#working-on-it). `bun run
typecheck` must be clean — it is its own CI step, and `any` is not a way past it.

## Interchange (local)

`bun run link:intx` symlinks `@intx/*` from a sibling `../interchange` checkout
(live `intx-src`, not npm `0.2.2`). Peer dependencies still declare
`@intx/agent` and `@intx/types`.

See [ARCHITECTURE.md](./ARCHITECTURE.md) for the delivery plan and non-goals.

## Tests

- **Red first.** A bug fix starts with a test that fails for the reason you believe,
and you should watch it fail.
- Assert **behavior a consumer can observe** over internal call shapes.
- Colocate tests next to the code they cover (`*.test.ts`).

## Pull requests

- Keep commits focused, and keep the diff to the change you are describing.
- Explain *why* in the commit message; the code already says what.
- CI must be green: typecheck, test, and build.
- Contributions are accepted under the repository's LGPL-2.1-only licence.
53 changes: 52 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,52 @@
Corbits Tools for X
# @corbits/x-tools

X API client and Interchange tools. Auth goes through Interchange credentials
(handle `x-api`). See [ARCHITECTURE.md](./ARCHITECTURE.md).

## Install

```bash
bun add github:corbitsdev/x-tools
# or pin a commit:
bun add github:corbitsdev/x-tools#<sha>
```

Not on npm yet; consume from git or an `npm pack` tarball. The repository root
*is* the package.

## Interchange

```json
"interchange": {
"tools": "./dist/sidecar-bundle.js",
"credentials": [{ "handle": "x-api" }]
}
```

Bind `x-api` on the agent definition to a tenant credential whose provider
origin is `https://api.x.com`. The sidecar resolves the mediated http handle
and never takes a raw secret on its options.

## Client

The internal client accepts an injected `fetchImpl`. The sidecar wires the
Interchange mediated credential, so this package never accepts a raw X token.

## Working on it

Requires a sibling checkout of Interchange at `../interchange`. Link its live
packages with `bun run link:intx`.

```bash
bun install
bun run link:intx
bun run typecheck
bun run test
bun run build
```

See [CONTRIBUTING.md](./CONTRIBUTING.md) and [ARCHITECTURE.md](./ARCHITECTURE.md).

## License

LGPL-2.1-only. See [LICENSE](./LICENSE).
17 changes: 12 additions & 5 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions bunfig.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Resolve Interchange packages to TypeScript source (same as Interchange itself).
[resolve]
conditions = ["intx-src"]
1 change: 0 additions & 1 deletion index.ts

This file was deleted.

67 changes: 62 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@
"version": "0.1.0",
"type": "module",
"license": "LGPL-2.1-only",
"description": "Corbits Tools for X",
"description": "Corbits Tools for X — X API client and Interchange tools.",
"keywords": [
"corbits",
"x",
"twitter",
"tools",
"interchange"
],
"author": "Corbits",
"homepage": "https://github.com/corbitsdev/x-tools#readme",
"repository": {
Expand All @@ -13,11 +20,61 @@
"bugs": {
"url": "https://github.com/corbitsdev/x-tools/issues"
},
"module": "index.ts",
"devDependencies": {
"@types/bun": "latest"
"engines": {
"node": ">=22"
},
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"bun": "./src/index.ts",
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./sidecar-bundle": {
"bun": "./src/sidecar-bundle.ts",
"types": "./dist/sidecar-bundle.d.ts",
"default": "./dist/sidecar-bundle.js"
}
},
"interchange": {
"tools": "./dist/sidecar-bundle.js",
"credentials": [
{
"handle": "x-api"
}
]
},
"files": [
"dist",
"src",
"!src/**/*.test.ts",
"LICENSE",
"README.md",
"ARCHITECTURE.md"
],
"sideEffects": false,
"scripts": {
"link:intx": "bun scripts/link-intx.ts",
"typecheck": "tsc -p tsconfig.typecheck.json --noEmit",
"build": "rm -rf dist && tsc -p tsconfig.build.json",
"prepack": "bun run build",
"test": "bun test --conditions intx-src src",
"test:client": "bun test --conditions intx-src src/client",
"test:tools": "bun test --conditions intx-src src/tools",
"test:coverage": "bun test --conditions intx-src --coverage src"
},
"peerDependencies": {
"typescript": "^5"
"@intx/agent": "*",
"@intx/types": "*"
},
"peerDependenciesMeta": {
"@intx/agent": { "optional": true },
"@intx/types": { "optional": true }
},
"devDependencies": {
"@types/bun": "1.3.14",
"@types/node": "22.10.5",
"typescript": "5.9.3"
}
}
Loading