---
name: treehouse-sdk
description: Build Treehouse-enabled apps using @treehouse/sdk — tenant-aware web apps, dashboards, and services that integrate with the platform via IPC. Use when the user wants to build an app that knows who they are, reads their credentials, deploys apps, sends messages, or communicates with the host platform.
---

# Building with @treehouse/sdk

`@treehouse/sdk` lets you build apps and scripts that are natively integrated with the Treehouse platform. They know your tenant identity, can read stored credentials, deploy apps, send messages to your chat, manage tasks, and more — all via the platform IPC.

## Adding the SDK

```json
{
  "dependencies": {
    "@treehouse/sdk": "file:/opt/treehouse/sdk"
  }
}
```

The SDK is pre-mounted at `/opt/treehouse/sdk` in every agent container — no install or bundling required. For tenant app containers, opt in with `sdk: true` per service in `app.yml` (see below).

## Core API

```typescript
import { getContext } from '@treehouse/sdk';

const { tenantId, ipcDir, workspaceDir } = getContext();
```

## Full API Reference

### Hosting info
```typescript
import { getHostingInfo, getAppStatus, getDeployErrors } from '@treehouse/sdk';

const info = await getHostingInfo();           // port range, IPC paths, commands
const status = await getAppStatus('myapp');    // deploy status for an app
const errors = await getDeployErrors(5);       // last N deploy errors
```

### App management
```typescript
import { deployApp, removeApp, stopApp, restartApp, execInApp, getAppLogs, listAppVolumes, removeAppVolume } from '@treehouse/sdk';

await deployApp('myapp');
await removeApp('myapp');
await stopApp('myapp');
await restartApp('myapp', ['api', 'proxy']);   // optional service filter
await execInApp('myapp', 'api', ['ls', '-la']);
await getAppLogs('myapp', 'api', 50);
await listAppVolumes('myapp');
await removeAppVolume('myapp', 'mongo-data');
```

### Messaging
```typescript
import { sendMessage, sendFile, sendVoice } from '@treehouse/sdk';

await sendMessage('Deployment complete!');
await sendMessage('Working...', { kind: 'progress' });
await sendFile('/workspace/group/report.pdf', 'Here is your report');
await sendVoice('Hello from your app');
```

### Tasks
```typescript
import { listTasks, scheduleTask, pauseTask, resumeTask, cancelTask, updateTask } from '@treehouse/sdk';

const tasks = await listTasks();
await scheduleTask({ prompt: 'Daily briefing', scheduleType: 'cron', scheduleValue: '0 9 * * *' });
await pauseTask('task-id');
await resumeTask('task-id');
await cancelTask('task-id');
await updateTask('task-id', { prompt: 'Updated prompt' });
```

### Groups
```typescript
import { registerGroup, updateGroupSettings } from '@treehouse/sdk';

await registerGroup({ jid: '...', name: 'My Group', folder: 'tenant/group', trigger: '@bot' });
await updateGroupSettings({ requiresTrigger: false });
```

### Runtime
```typescript
import { pruneRuntime, getDiskUsage, resetBuildkit } from '@treehouse/sdk';

await pruneRuntime('builder');   // builder | images | images-all | volumes | all
await getDiskUsage();
await resetBuildkit();
```

### Credentials
```typescript
import { getCredential, listCredentials } from '@treehouse/sdk';

const key = await getCredential('github-api-key');
const all = await listCredentials();
```

## Using the SDK in tenant app containers

By default, tenant app containers do not have access to the SDK or platform IPC. To opt in, add `sdk: true` to a service in your `app.yml`:

```yaml
services:
  api:
    sdk: true
    build:
      context: .
    internal_port: 3000
    public: true
```

When `sdk: true` is set, the platform automatically injects:
- `/opt/treehouse/sdk` — SDK mount (read-only)
- `/workspace/ipc` — IPC directory (read-write)
- `TENANT_ID`, `NANOCLAW_GROUP_FOLDER`, `NANOCLAW_CHAT_JID` — context env vars

Your app can then use `@treehouse/sdk` normally:

```typescript
import { sendMessage, deployApp } from '@treehouse/sdk';

// Called from within your tenant app container:
await sendMessage('Build finished!');
```

> Only enable `sdk: true` on services that actually need platform access (e.g. your API service, not a Postgres sidecar).

## Example: Express app with SDK

```typescript
import express from 'express';
import { getContext, sendMessage } from '@treehouse/sdk';

const app = express();
const ctx = getContext();

app.post('/notify', async (req, res) => {
  await sendMessage(`Alert from ${ctx.tenantId}: ${req.body.message}`);
  res.json({ ok: true });
});

app.listen(3000);
```

## Notes

- SDK updates are live immediately — the host mount is updated without container rebuilds
- `TENANT_ID` is always set; `NANOCLAW_GROUP_FOLDER` and `NANOCLAW_CHAT_JID` are set in agent containers and in app containers that opted in with `sdk: true`
- Use `tc` in agent containers for CLI access to the same functionality
