Kody kody.codes

I Built Your Personal Software Ecosystem

Human β†’ Agent β†’ Software

Kent C. Dodds
Kody, the official kody.codes koala

Please stand up.

Your 🧠 needs this

How will you give your job to your agent?

You've got work to do

Do it the hard way first

Pain motivates a move

Agents hide the pain.

Time Cost Scale Focus
Cost Reliability Safety Durability
Time Cost Scale Focus

Walled Gardens

One shared software ecosystem

Software
Software
Software
Software
Software
Software
Software
Software
Software
🐨 Software
Human
Stop sweating agent switching

Problem

Infinite capabilities can't fit in MCP tools

search


search({ query: "close the shades" })
								

# Search results

For full detail on entity-backed hits, call `search` with `entity: "{id}:{type}"`.

1. **package** @kentcdodds/home-controls (`home-controls`) β€” Package-first home helpers for TV app launching, TV power, Roku YouTube playback, Frame Art Mode, and Bond shade controls by area or room. Entity: `home-controls:package` Best action: `default` via `import action from "kody:@kentcdodds/home-controls/bond-area-shades"` β€” Open, close, stop, or position every Bond shade in a named home area. Returns `{ ok, area, affected, results }` on success or `{ ok: false, error }`. @example import bondAreaSha...
2. **package** @kentcdodds/shade-automation (`shade-automation`) β€” Daily solar shade planning, Bond control, disconnect alerts, and a mobile control-center app. Entity: `shade-automation:package` Best action: `default` via `import action from "kody:@kentcdodds/shade-automation/control"` β€” Move shades from the control-center app or a package invoke. The hosted app calls Bond in-process; this export is the same write path for MCP and other package runtimes. @exampl...
3. **mcp-server** home (`mcp:home`, 206 tools) β€” Home MCP server for local-network devices, including an Android phone companion over WebSocket at /phone/ws. Tools stay on this process; Kody connects over Streamable HTTP at /m... Entity: `home:mcp-server`. List tools with `search({ entity: "home:mcp-server" })`. Call via `kody.mcp["home"].tool_name(args)`. Wrapping package: `@kentcdodds/home-controls` (Entity: `home-controls:package`).
4. **capability** `waitingSummary` (`account`) β€” List things currently waiting on the signed-in human: email verification, OAuth reconnects, expired secrets, MCP reconnects, locked-package publishes, plan caps, wizard resume,... Entity: `waitingSummary:capability`
   `kody.waitingSummary(args)` β€” `type WaitingSummaryInput = Record<string, never>`
5. **secret** `homeMcpOperatorPassword` β€” HOME_MCP_OPERATOR_PASSWORD for kody-home.doddsfamily.us /authorize. Entity: `homeMcpOperatorPassword:secret`

## Relevant memories

- **Home shade automation intent** β€” Shade automation maximizes natural light with a daily sun-position planner for privacy, heat, and glare events; weather-sensitive moves decide from current cloud cover at event time (no cloud-watch polling). Office recording protection applies; master suite is never automated; kitchen-door rules preserve door access and vacuum clearance. Canonical behavior spec is INTENT.md in @kentcdodds/shade-automation.
								

search({ entity: "home-controls:package" })
								

# Package β€” `home-controls`

Package-first home helpers for TV app launching, TV power, Roku YouTube playback, Frame Art Mode, and Bond shade controls by area or room.

## Index

- Entity: `home-controls:package`
- Package name: `@kentcdodds/home-controls`
- Tags: `home`, `tv`, `samsung`, `frame-tv`, `roku`, `youtube`, `bond`, `shades`
- Has app: no
- Hidden: no

## Exports

| Subpath | Purpose |
| --- | --- |
| `./bond-area-shades` | Open, close, stop, or position every Bond shade in a named home area. Returns `{ ok, area, affected, results }` on success or `{ ok: false, error }`. @example import bondAreaShades from 'kody:@kentcdodds/home-controls/bond-area-shades' const result = await bondAreaShades({ area: 'back', action: 'close' }) // => { ok: true, area: 'back', affected: ['Kitchen South', ...], results: [...] } |
| `./bond-room-shades` | Open, close, stop, or position Bond shades in one room, optionally filtered by sheer/blackout type. Returns `{ ok, room, type, affected, results }` on success or `{ ok: false, error }`. @example import bondRoomShades from 'kody:@kentcdodds/home-controls/bond-room-shades' const result = await bondRoomShades({ room: 'Office', type: 'sheer', action: 'open' }) // => { ok: true, room: 'Office', type: 'sheer', affected: [...], results: [...] } |
| `./frame-art-mode` | Read or toggle Samsung Frame TV art mode for Kent's living-room Frame. Returns `{ ok, deviceId, deviceName, mode?, result }` or `{ ok: false, error }`. @example import frameArtMode from 'kody:@kentcdodds/home-controls/frame-art-mode' const result = await frameArtMode({ room: 'frame', mode: 'on' }) // => { ok: true, deviceId: 'samsung-tv-uuid-...', deviceName: '65" The Frame', mode: 'on', result: ... } |
| `./roku-play-youtube` | Launch the YouTube app on a named Roku and start playing a video by id or URL. Returns `{ ok, deviceId, deviceName, videoId, result }` or `{ ok: false, error }`. @example import rokuPlayYoutube from 'kody:@kentcdodds/home-controls/roku-play-youtube' const result = await rokuPlayYoutube({ deviceName: 'Theater', videoId: 'dQw4w9WgXcQ' }) // => { ok: true, deviceId: 'roku-x...', deviceName: 'Theater', videoId: 'dQw4w9WgXcQ', result: ... } |
| `./tv-power` | Turn a Samsung Frame TV or named Roku on or off via the home connector. Returns `{ ok, platform, deviceId, deviceName, state, result }` or `{ ok: false, error }`. @example import tvPower from 'kody:@kentcdodds/home-controls/tv-power' const result = await tvPower({ room: 'theater', state: 'on' }) // => { ok: true, platform: 'roku', deviceId: 'roku-x...', deviceName: 'Theater', state: 'on', result: ... } |
| `./tv-watch-app` | Launch a streaming app on a Samsung Frame TV or named Roku by app name or app id. Returns `{ ok, platform, deviceId, deviceName, appId, result }` or `{ ok: false, error }`. @example import tvWatchApp from 'kody:@kentcdodds/home-controls/tv-watch-app' const result = await tvWatchApp({ room: 'frame', app: 'Netflix' }) // => { ok: true, platform: 'samsung', deviceId: 'samsung-tv-uuid-...', appId: '3201907018807', result: ... } |

## Agent docs (`AGENTS.md`)

# @kentcdodds/home-controls β€” agent notes

Human setup and intent live in [`README.md`](./README.md). This file is for
agents: imports, smoke checks, snippets, and edge cases. Secrets by **name**
only β€” never paste key values. Do not disable live webhooks or jobs.

## Secrets

None declared via `{{secret:…}}` placeholders in this package source. Check README / deps for upstream secrets.

## Import paths

| Export | Import |
| --- | --- |
| bond-area-shades | `kody:@kentcdodds/home-controls/bond-area-shades` |
| bond-room-shades | `kody:@kentcdodds/home-controls/bond-room-shades` |
| frame-art-mode | `kody:@kentcdodds/home-controls/frame-art-mode` |
| roku-play-youtube | `kody:@kentcdodds/home-controls/roku-play-youtube` |
| tv-power | `kody:@kentcdodds/home-controls/tv-power` |
| tv-watch-app | `kody:@kentcdodds/home-controls/tv-watch-app` |

Prefer static `kody:@kentcdodds/home-controls/...` imports from `execute`.
Do not lead with `packages.invoke`.

## Smoke / dry-run

Root/overview (prefer read-only describe when available):

```js
import mod from 'kody:@kentcdodds/home-controls/bond-area-shades'

export default async function main() {
	return await mod()
}
```

## Edge cases…

> AGENTS.md was truncated for this index.

## Follow up

If you plan to invoke an export, call packageGet({ package_id: "e24de5c2-8622-40ce-9bf1-6664be204901" }) first for the exact call shape, types, and package-scoped secret metadata. That call does not return files. For the full README.md, AGENTS.md, and source, open a repo session with repoOpenSession({ target: { kind: "package", package_id: "e24de5c2-8622-40ce-9bf1-6664be204901" } }) then repoReadFile({ session_id, path: "README.md" }) and repoReadFile({ session_id, path: "AGENTS.md" }) (browse other files with repoTree). Discard the session with repoDiscardSession when finished. If you have a local git client, call packageGetGitRemote({ package_id: "e24de5c2-8622-40ce-9bf1-6664be204901" }) instead and clone. search({ entity: "package_authoring:guide" }) covers inbound webhooks and maintenance workflows.
								

search({
  entity: "package:home-controls#bond-area-shades",
})
								

# Package export β€” `home-controls` / `bond-area-shades`

Open, close, stop, or position every Bond shade in a named home area.

Returns `{ ok, area, affected, results }` on success or `{ ok: false, error }`.

## Summary

- Entity: `package:home-controls#bond-area-shades`
- Package name: `@kentcdodds/home-controls`
- kody_id: `home-controls`
- Import: `kody:@kentcdodds/home-controls/bond-area-shades`

## Execute from `execute`

```ts
import action from "kody:@kentcdodds/home-controls/bond-area-shades"

export default async function main(params) {
	return await action(params)
}
```

## Type definition

```ts
export default function bondAreaShades( params?: BondAreaShadesParams, ): Promise<BondAreaShadesResult>
```

## Referenced types

```ts
export type BondAreaShadesParams = {
	/** Named home area. */
	area?: BondAreaName
	/** Shade action: Open, Close, Stop, or SetPosition (aliases accepted). */
	action?: string
	/** Target position 0–100 when action is SetPosition. */
	position?: number
	/** Relative position change -100 to 100 instead of an absolute action. */
	delta?: number
}
export type BondAreaShadesResult = {
	area?: 'back'
	ok: boolean
	error?: string
	availableAreas?: Array<'back'>
	affected?: string[]
	results?: Array<Record<string, unknown>>
}
export type BondAreaName = 'back' | 'backyard'
```

## Example

```ts
import bondAreaShades from 'kody:@kentcdodds/home-controls/bond-area-shades'
const result = await bondAreaShades({ area: 'back', action: 'close' })
// => { ok: true, area: 'back', affected: ['Kitchen South', ...], results: [...] }
```

## Follow up

packageGet({ package_id: "e24de5c2-8622-40ce-9bf1-6664be204901" }) returns the full export array plus package-scoped secret metadata. That call does not return files.
								

execute


import bondAreaShades from
  "kody:@kentcdodds/home-controls/bond-area-shades"

export default async function main() {
  return await bondAreaShades({
    area: "back",
    action: "close",
  })
}
								

{
  ok: true,
  area: "back",
  affected: ["Kitchen South"],
}
								

How execute works

Cloudflare Dynamic Workers mark
%%{init: {'themeVariables': {'fontSize': 24}, 'sequence': {'mirrorActors': false, 'actorFontSize': 24, 'messageFontSize': 24, 'noteFontSize': 22, 'width': 168, 'height': 54, 'actorMargin': 62, 'messageMargin': 30}}}%%
sequenceDiagram
	actor Agent
	participant Kody as Kody worker
	participant Loader
	participant Isolate
	Agent->>Kody: execute({ code })
	Kody->>Kody: bundler
	Kody->>Loader: modules
	Loader->>Isolate: load
	Isolate->>Kody: code-mode
	Kody->>Isolate: code-mode
	Kody-->>Agent: result
							

// worker.ts
const modules = {
  "executor.js": codeExecutor,
  "entry.ts": bundledCode,
}

const isolate = loader
  .get(workerId, () => ({ modules }))
  .getEntrypoint()

const dispatchers = {
  kody: capabilities, // emailSend, secretList, …
}

const { result } = await isolate
  .evaluate(dispatchers)
									

// executor.js
export default class CodeExecutor {
  async evaluate(__dispatchers = {}) {
    const kody = new Proxy({}, {
      get: (_, name) => async (args) => {
        const resJson =
          await __dispatchers.kody.call(
            name,
            JSON.stringify(args),
          )
        const data = JSON.parse(resJson)
        if (data.error) {
          throw new Error(data.error)
        }
        return data.result
      },
    })
    return { result: await userCode({ kody }) }
  }
}
									

How would you solve the MCP tool limit?

Problem

Agents see your secrets

Agents only write secret references


export default async function main() {
  const response = await fetch(
    "https://api.github.com/user/repos?per_page=5",
    {
      headers: {
        Authorization: "Bearer {{secret:githubAccessToken}}",
      },
    },
  )
  return response.json()
}
						

How the gateway works

%%{init: {'themeVariables': {'fontSize': 24}, 'sequence': {'mirrorActors': false, 'actorFontSize': 24, 'messageFontSize': 24, 'noteFontSize': 22, 'width': 168, 'height': 54, 'actorMargin': 62, 'messageMargin': 30}}}%%
sequenceDiagram
	actor Agent
	participant Isolate
	participant Gateway
	participant GitHub
	Agent->>Isolate: execute({ code })
	Isolate->>Gateway: fetch + placeholder
	Gateway->>Gateway: Replaces the token
	Gateway->>GitHub: Bearer token
	GitHub-->>Gateway: 200
	Gateway-->>Isolate: body
							

How would you solve agents seeing secrets?

Problem

Skills aren't software

They're just prompts you pay for every time πŸ’Έ

Code composes


import closeShades from
  "kody:@kentcdodds/kitchen-shade-control/close-shades"
import runMorningBriefing from
  "kody:@kentcdodds/morning-briefing"
import { getEpisode } from
  "kody:@kentcdodds/transistor"

export default async function main(input) {
  const shades = await closeShades()
  const briefing = await runMorningBriefing({ dryRun: true })
  const episode = await getEpisode({ episodeId: input.episodeId })
  return { shades, briefing, episode }
}
						

How the import works

%%{init: {'themeVariables': {'fontSize': 24}, 'sequence': {'mirrorActors': false, 'actorFontSize': 24, 'messageFontSize': 24, 'noteFontSize': 22, 'width': 168, 'height': 54, 'actorMargin': 62, 'messageMargin': 30}}}%%
sequenceDiagram
	actor Agent
	participant Kody as Kody worker
	participant Loader
	participant Isolate
	Agent->>Kody: execute({ code })
	Kody->>Kody: published commit
	Kody->>Kody: bundle + npm + deps
	Kody->>Loader: modules
	Loader->>Isolate: load
	Isolate-->>Kody: result
							

How would you solve skills that aren't software?

Problem

Irritating setup for every script

Primitives to build anything


import { createAuthenticatedFetch, kody, packageStorage,
  workflows } from "kody:runtime"

export default async function main() {
  const since = await packageStorage().get("sinceId")
  const gh = await createAuthenticatedFetch("github")
  const res = await gh("https://api.github.com/user")
  const me = await res.json()
  await workflows.create({ exportName: "./rebuild-index",
    params: { login: me.login, since } })
  return kody.emailSend({
    subject: `${me.login} digest`,
    text: `since ${since ?? "start"}`,
  })
}
								

{
  "kody": {
    "jobs": {
      "daily-digest": {
        "entry": "./daily-digest.ts",
        "schedule": { "type": "cron", "expression": "0 7 * * *" },
        "timezone": "America/Denver"
      }
    },
    "webhooks": [{
      "name": "github",
      "export": "./on-github",
      "verification": {
        "type": "hmac-sha256",
        "secretName": "githubWebhookSecret"
      }
    }],
    "subscriptions": {
      "email.message.received": { "handler": "./on-email.ts" }
    }
  }
}
								

Built on

  • Cloudflare Workers
  • Cloudflare Workflows
  • Durable Objects (Distributed SQLite)
  • Cloudflare Email

How would you solve setup for every script?

Problem

Agents pressing buttons is expensive

Package Apps for UI


{
  "kody": {
    "app": {
      "entry": "./app/router.ts",
      "client": "./app/assets/entry.ts",
      "assets": "./public"
    }
  }
}
						

package-app-kit

  • travel-map
  • morning-briefing
  • rotosphere
  • audible
  • court-projector
  • swipe
  • raycast
  • mailroom
  • shade-automation

Built on

  • Cloudflare Workers
  • Remix
  • Durable Objects
  • Service Workers
  • WebSockets

How would you solve expensive button presses?

How will you give your job to your agent?

Kody holding a lantern
kody.codes

You're awesome

Thank you

kody.codes

Kody, the official kody.codes koala