Skip to content
dannybrianPublic

About

A conversational harness for director agents, using Claude Code SDK and ElevenLabs voices.

Resources

Stars

3 stars

Watchers

2 watching

Forks

Latest commit

Β 

History

167 Commits

Folders and files

Repository files navigation

Beth,Β a director agent harness

Yes another harness. But the one that fits my brain and workflows, talks to me about things I want to know, and keeps me on task. (And does so with zero dependencies other than the SDKs.) On a mature (or simply large enough) software project, especially as a solo developer, trying to actively manage more than 5-6 agents (I've had well over 20 going on a single project), trying to spend a week's worth of tokens over the weekend, manage worktrees and streams and dependencies... well, then it might be time for a director.

Too Well Paid to Code

Beth is not much of a builder. Like you (and me), she (too) uses agents to help her write code; she is a director in the builder pattern. And totally and completely unnecessary to that pattern, I might add! She needs frontier models and might work off hours; Beth will not save you money, only time. A director harness does this by focusing my attention, and that was the design goal here; coordination was secondary.

Beth is not needed. πŸ€·β€β™‚οΈ No project depends on her. πŸ€·β€β™‚οΈ In fact, neither I nor the agents like her very much. πŸ€·β€β™‚οΈπŸ€· (I will readily admit my tendency to anthropomorphize; the incongruity of "don't like her" was a joke she found funny. And frankly saying "it" doesn't quite work here, either. I work with .. it, quite a bit. Anyway, I will try to refrain from the pronouns.)

But she knows how to sequence, how to manage agents effectively, how to manage both our expectations, how to manage me, and is able to carry a higher, additional level of context and reasoning on behalf of those she manages, so they don't need to. She will work in to the evening hours. It's a question of scale, the need for additional agentic judgement in the loop to do so, and a scale I don't think many projects achieve, or require. In other words, don't use this instead of CC just because it talks. Or do. I don't care. Neither does it, I'm told by people who I trust.

A director agent must be status-aware, and capable of planning, modifying, tracking, and coordinating. And because you want it capable of doing this across multiple plans, that means context about many things β€” just not implementation. Beth makes zero assumptions about what those plans are β€”Β they could be detailed specs, they could be plans that still need specs, or they could be umbrella placeholders for upcoming tasks. (However, the sweet spot is plans for features and enhancements on an existing platform/project.)

What This Is Not

  • Not an orchestrator. Conductor, Vibe Kanban, Claude Code's own Squad and Agent Teams manage many parallel sessions β€” worktrees, dashboards, merge queues. Beth is the opposite bet: one standing director with judgment, who happens to dispatch workers. If your bottleneck is parallelism plumbing, use those; mine was attention.
  • Not an issue tracker. Beads exists precisely because piles of markdown plans go stale, and Backlog.md does markdown-as-source-of-truth properly (and I might use one eventually). This harness takes no side: it defines the shape of a work item (workItems.ts) and reads it through a small contract β€” /plans is the built-in reader because dated markdown is my convention across my repos. A repo that lives in Linear, beads, or GitHub issues would supply its own reader; the panel doesn't care.
  • Not voice mode for coding. Claude Code's /voice is dictation in. This is conversation β€” she talks back, in a voice that's hers, excerpted because ninety seconds of unskippable audio is not six paragraphs of skimmable text. And because the harness uses an in-process MCP, saying out loud "I'm on a call, shhh" will deactivate or activate such settings at the client. A director agent benefits from speech; a coding agent, less so.

Everything here is opinionated, and the opinions are mine. Where I expect yours to differ, the seam is marked. This is what evolved for me in my own workflows.

Benefits No One Without a Platform

A director agent's time/tokens and the tokens its subagents spend are wasted on errors, bugs, or other problems encountered during execution. This is not just a question of proper context or prompting; it's the likelihood of agents having success without their own retries or ratholes. This comes at an up-front cost of quality (of all kinds; think beyond tests towards telemetry etc.) for the repos in which a director agent can work. Of all the hurdles to my using AI more effectively for development, this is the one that most necessitated my need for a director agent: As the quality of a project increased, so did execution velocity. I was always the bottleneck. But once a platform is in place β€” something underneath to have already made the important decisions and answered the important questions β€” and knowing it was being done how I wanted, fully validated as such, I could step back a little.

What this harness does not do: Ensure code quality, care about best practices, or, well, write good code, per se. Beth couldn't really care less how anything happens under the hood. Implementation, TDD, debugging, coding guidelines are not things provided here; those exist in your repo. Beth can help you build that all out, but won't do it for you.

What this harness does: Beth gives you a standing director on a single repo: someone who has already read the board, knows what shipped yesterday, holds the shape of the work while you hold a coffee, and can be talked to out loud while you pace. Basically, it fills in a lot of coordination, SDLC gaps. Claude Code and other tools give you a coding session (and I use it actively in parallel); what they don't give you is the assistant across from you β€” a name, a voice, a memory of me, an opinion about what I should do next, and a place to see the work together, while we argue about it. Beth cares about plans and managing their execution, and little else.

How I Use It

% beth, run from a repo root:

A director session: Johnny shipping a feature end to end on a music platform repo β€” narrated verification in the transcript, an event card linking its plan, and pending decisions, two workers, and the plans board on the panel.

Beth integrates with ElevenLabs for voice, and you can set the chattiness. Multiple personas can be defined, each with its own voice from your ElevenLabs account.

Beth tracks token use β€” context, per-turn and session cost, the plan's usage windows, and an itemized speech bill β€” behind the context meter. It also provides an under-the-hood visualization of token consumption, cache reads/writes, and thinking, which I find useful mainly for demonstration and education.

The wire panel: one turn as nine API requests β€” an anatomy strip of thinking, writing, and tools; stacked token bars showing cache writes becoming cache reads; and the raw exchange underneath.

The harness can also run the repo's tests automatically, so status is a glance away and failures are easy for Beth to dig into. It doesn't act on results by itself β€” no automatic troubleshooting, by design.

Director Agent

Beth puts an emphasis on planning, implementation oversight, and autonomous execution -- and expects a well-documented, well-tested workflow under that to make it happen. The harness edits, maintains, updates, indexes, and displays ... well, plans.

Coordinator/director agents like this work best when taught the "lanes" of a project -- where it's probably better to run one subagent at a time, what can and can't be done in parallel, where worktrees are in flight and why, and how to prioritize and queue all of that. And this is largely because they can see all the plans and exercise judgement about them (just as with a DevOps agent platform), but it's also because a director will understand the broader goals or requirements -- for this reason Beth provides a plan hierarchy, for umbrella plans, subplans, and so on.

Beth can then surface pending questions or call for your attention, maintaining a queue across many plans and subagents β€” pending decisions each carry the plan they belong to, and running workers show up beside them with a close control.

One consequence of queuing up issues for you is that Beth's interactions with subagents are more frequent and often narrowly-scoped: the director pattern incurs token cost, and benefits most from the best reasoning models. It costs to scale -- and it won't work at all if subagents can't have their work narrowly scoped with good repo organization, modularity, testing, and documentation. Exploration is expensive, and the director pattern does little to change that.

Underlying Skills

This repo includes the /plans and /tidyrepo skills I use. The /plans skill is what understands the plan file formats and indexing, and Beth's UI is built on that (and tidyrepo is used by the director periodically). However, the director still presumes a lot of discipline in a project's own documentation, skills, and so on. For example, clearly defined TDD/validation contracts throughout the documentation and skills that subagents will use. A director workflow only works after demonstrated success with these highly project-specific guardrails. In other words, you're unlikely to use Beth to bootstrap a new project (or at least, I haven't yet), and if you do, the conversation would start with planning to build those contracts, guidelines, clear testing strategies, and docs/skills to maintain them. See below for details on bootstrapping a new project using /director-skills.

(For me, markdown hits the mark for this kind of work. If your source of truth is JIRA, GitHub issues, or something else with an API, the seam is workItems.ts: the harness defines the shape of a work item, /plans is just the built-in reader, and a reader of your own feeds the same panel. See What This Is Not, above. There is a second built-in reader that shows the shape: the inbox, below.)

cd ~/Sources/your-project && beth

That binds to the git root you are standing in, picks a free port (several repos run side by side), opens the browser, and tears everything down on Ctrl-C. beth --help for flags.

The design is one contract with three suppliers, and almost everything about the harness falls out of it:

  • The harness supplies the ROLE β€” an expert project manager who converses instead of reporting, narrates before anything slow, and protects your attention. It is project-agnostic on purpose and ships with opinions about how to direct, none about what.
  • Your repo supplies the PERSON and the WORK β€” who the director is (.claude/DIRECTOR.md) and what is in flight (plans/). The harness only ever reads your repo β€” the director session it hosts writes code and commits through permission gates, like any Claude Code session (see Anatomy).
  • Your machine supplies the IDENTITIES β€” credentials, and optionally personas: directors of your own that exist across every repo, with their own voices and their own memory of you (~/.director-harness/personas/).

Anatomy

The client is stateless, refreshes don't underrupt anything (beyond voice, something being spoken). So, you can also open the same session in multiple browsers, or remotely (zero security provided here).

Everything Beth says and hears crosses one loopback listener:

%%{init: {"themeVariables": {"fontSize": "13px"}, "flowchart": {"nodeSpacing": 28, "rankSpacing": 34, "padding": 6}}}%%
flowchart TB
  subgraph BROWSER["Chrome β€” the room (loopback only)"]
    EAR["πŸŽ™ the mic<br/>capture.js"]
    UI["the page<br/>transcript Β· panels"]
    MOUTH["πŸ”Š the mouth<br/>speaker.js"]
    EAR ~~~ UI ~~~ MOUTH
  end

  subgraph HARNESS["beth β€” one Node process per repo"]
    SRV["server.ts<br/>the one listener"]
    STT["earHost.ts<br/>src/ear/ (Scribe)"]
    SES["session.ts<br/>one SDK query"]
    MCP["tools.ts<br/>in-process MCP"]
    TTS["speakOut.ts"]
    TAP["wireTap.ts"]
    SRV --- STT
    SRV --- SES
    SES --- MCP
    SES --- TAP
    SES --- TTS
  end

  CC["Claude Code CLI<br/>Agent SDK"]
  ANTH(["Anthropic API"])
  XI(["ElevenLabs<br/>STT + TTS"])

  EAR -->|"PCM"| SRV
  STT <-->|"recognise"| XI
  UI <-->|"SSE + POST"| SRV
  SRV -->|"mp3 stream"| MOUTH
  SES <--> CC
  CC <--> ANTH
  TTS -->|"one line"| XI
Loading

This harness only ever reads your repo (subagents will read and write):

%%{init: {"themeVariables": {"fontSize": "13px"}, "flowchart": {"nodeSpacing": 28, "rankSpacing": 34, "padding": 6}}}%%
flowchart TB
  subgraph HARNESS["beth"]
    SES2["session.ts"]
    IDX["the work index"]
    CC2["Claude Code CLI"]
    SES2 ~~~ IDX ~~~ CC2
  end

  subgraph REPO["your repo β€” read only"]
    PLANS["plans/*.md"]
    DIR[".claude/DIRECTOR.md"]
    PROJ["CLAUDE.md Β· skills"]
    PLANS ~~~ DIR ~~~ PROJ
  end

  subgraph HOME["your machine β€” ~/.director-harness"]
    PERS["personas/*.md"]
    MEM["Beth's memory of you<br/>persona-state/, or the repo's"]
    PERS ~~~ MEM
  end

  IDX -->|"watches"| PLANS
  SES2 -->|"system prompt"| DIR
  SES2 -->|"system prompt"| PERS
  SES2 <-->|"remembers"| MEM
  CC2 -->|"loads"| PROJ
Loading

Every arrow touching your repo is a read, with two named exceptions: a rename you click writes one frontmatter key into that plan file, and the harness appends its event log to .claude/events.jsonl (keep it gitignored β€” /director-skills sets that up) so events survive a restart. Nothing else in the plumbing writes into the repo. That is a claim about the harness plumbing, not the whole system, obviously: the Claude session it hosts dispatches workers that write code and commit, exactly as any Claude Code session would β€” through the same permission gates. The safety story is the gate, not read-onlyness. The browser and the harness speak over one loopback listener β€” voice included β€” which is why the shell-executing parts are safe by construction rather than by rule. (Plus an Origin check on every API write, because a loopback port is still reachable by any page your browser has open.)

Getting a repo ready: /director-skills

The fastest way to see it working is a repo that supplies its half of the contract β€” and rather than document the formats in prose (which would drift from the parser the moment either changed), the repo half ships as a skill that sets it up with you:

ln -sf ~/Sources/beth/skills/director-skills ~/.claude/skills/director-skills

Then, in any repo, ask its director (or any Claude Code session) to run /director-skills. It diagnoses before it writes: a repo with plans the harness cannot read gets told why (often the fix is one env line); a greenfield repo gets the format bootstrapped from managed templates β€” the plans directory, the frontmatter schema, a vendored copy of the /plans session tracker with its tests, /tidyrepo β€” and a director interviewed into existence, because a person is the one thing a template cannot supply. The harness will also offer this itself, once, when it boots against a repo with nothing to read β€” with evidence, not as a wizard.

The reasoning is in docs/director-skills.md. This repo's own .claude/DIRECTOR.md is the worked example of the interview's output.

Talking To Beth Be Like

Heading was her idea. Text here works like any chat, with three differences:

  • The panel is shared ground. Clicking a plan's name opens it to read; the β†’ beside it points at it β€” Beth gets the reference, you get a chip, and "what's left on this?" needs no name. Clicking a failing test points the same way. Rows carry a pin, a rename, and one-click handoff to a fresh Claude Code terminal session seeded with the plan.
  • Decisions queue instead of interrupting. Anything Beth wants decided but isn't blocked on lands in a queue with candidate answers as buttons. Both of you can close items; a queue with settled things in it stops being read.
  • Beth narrates. Several modes for voice let me hear what I want, although this needs some refinement. I want the updates like, "hold on, running the suites", and hearing the report when it lands. It's something I'm sure other harnesses have done, and that some vendors provide, or will β€” it's something that benefits a director harness more than any other dev workflow would, in my opinion.
  • I'm still learning how best to use it. I have to speak differently to Beth; it's easy to go down a rathole, or ask Beth to do something I should probably be doing with Claude Code (e.g. an implementation I haven't thought through or prepared for) or myself. Then something comes up in another workstream and my director is blocked on a rathole with me, and time is lost. So, Beth works best when plans (and if complex, implementation plans too) are written elsewhere, since those tend to require her focus.

Voice stays on loopback. The page captures your microphone and streams it to the harness (ui/capture.js), which recognises over ElevenLabs Scribe v2 realtime (src/ear/) β€” punctuated, cased, biased toward the project's own nouns, with utterances ended by real voice-activity detection instead of a guessed pause. Beth's replies stream back the same way as audio (src/speakOut.ts). Nothing dials in, nothing tunnels, nothing is billed while idle, one listener bound to 127.0.0.1; listening meters by the second (~$0.39/hr, itemised in the stats panel). Without an ELEVENLABS_API_KEY β€” or with HARNESS_EAR=browser, or when Scribe degrades mid-conversation β€” the ear falls back to Chrome's free Web Speech path (ui/listen.js): no punctuation, audio to Google, Chrome only. Speech out is an excerpt (the page skims in seconds what audio cannot skip), the mic ducks reasoning effort for latency, and an autosend toggle turns conversation into dictation when you want to edit before sending. docs/ear.md and docs/voice-plane.md have the full story, including everything this replaced.

Beth speaks in whatever voice the persona names (voice:), falling back to HARNESS_VOICE_ID β€” one durable answer, in her file, and no picker anywhere in the page to disagree with it. The key needs the Text to Speech permission β€” without a key the harness runs text-only and the mic button explains what is missing.

Personas

~/.director-harness/personas/*.md β€” one markdown file per director, none shipped. Frontmatter names the director and the voice. A repo's DIRECTOR.md still composes on top: the persona says who the director is, the repo says what this project needs, and the repo wins where they overlap. Beth's memory of you follows the persona (switching repos doesn't reset the relationship); greeting habits stay per-project. Switching personas is a new conversation β€” the page warns you β€” because a system prompt is fixed at session birth, and you don't swap who you're talking to mid-thought.

An existing DIRECTOR.md copied into that directory is a valid persona β€” the name is read from the same "You are X" sentence.

What Beth remembers, and when it asks

personal.jsonl, append-only, never in your repo. The rule that keeps it from being a rapport script: Beth may only ask about something it actually recorded β€” a question comes from a fact with a date on it, at most once a day, and only at a natural moment β€” the boot greeting, or the first turn after a long gap. Most days that is silence, which is correct. HARNESS_PERSONAL=off means off: nothing recorded, nothing asked.

The greeting itself is model-written, one sentence, made different each day by the two things a fresh session can't otherwise have: what it opened with recently ("not these"), and the facts that changed β€” branch, dirt, last commit, what's in flight, the clock, the gap since the harness was last up.

(And yeah, I considered using a common memory library or data "lake" here, but I like that there are no dependencies beyond the two vendor SDKs. And again, nobody needs Beth.)

The rest of the surface

  • Tests: the top-right light detects the project's test command (never invents one), runs it when the tree settles and the session is idle, and is off until you enable it per repo β€” this executes project code on a schedule. Clicking a failure drops a chip, not a stack trace; beside it a β‡₯ button pastes the thing itself β€” one failure, or the whole run β€” into the composer, unsent and with the byte count on the button, for when the answer is in the output and nothing short of the output will do. The build panel has the same control, where it matters more: with no parser there, it is the only way a build reaches her with its reasons attached.
  • Reading a plan: the β–€ on a row (or clicking a plan Beth mentions) opens it in the harness β€” the markdown rendered at a size meant for reading, with rename, pin and handoff along the top, plus β†’ to point Beth at it and βŒ– to find it on the board. Read-only on purpose: the checkboxes are disabled, because the harness does not write plan files.
  • The inbox: other agents and apps can hand the director work. A producer appends one JSON line per hand-off to a file β€” ~/.director-harness/inbox/*.jsonl, or a file it keeps itself, named by HARNESS_INBOX β€” and every running director reads every file. No API, no discovery: a record's to is a director's name, an unaddressed one is for everyone, and the harness never learns who wrote it. Hand-offs lead the plans panel in their own group, unfold in place (there is no file behind one), and are closed with βœ“/Γ— on the row or by Beth with close_inbox; the acknowledgement lives in the state dir, and the producer's file is never touched. Arrival is a summons β€” spoken, once β€” and the backlog at boot is not. docs/inbox.md has the record shape and the reasoning.
  • /restart in the composer: the harness exits cleanly and the beth wrapper starts it again on the same port, picking up whatever code is on disk; the page reconnects by itself and the session resumes. Refused while a turn or a worker is running, because both would die with the process. Not hers to call, on purpose.
  • A bell: a soft synthesised tone when a turn finishes, toggled beside the volume. Deliberately not governed by the voice mute β€” that one is about her voice and about not being billed, and the bell matters most when she is silent.
  • Permission cards: tool calls the session can't settle on its own become cards; a card cannot be answered by voice, so the session defaults to the SDK's auto mode and "Always" scopes its rule to the session β€” never written to your repo's settings from a button.
  • Director-role handoff: if a terminal session already holds the director plan, the harness comes up as a shadow β€” read everything, claim nothing. Promotion re-checks at the moment you click it.
  • The strip: the plan's five-hour and seven-day windows and this session's context, model, reasoning effort, speech level, persona β€” all live, all showing what the server believes rather than what was clicked. Two lights on the right: tests and build β€” click to look, keypad 1 and 2 to fire β€” and the same light again in the tab title, where it is the only part of the page you can see while looking at something else. The tab also front-loads what wants you: (N) for queued decisions, and ❗ when Beth is stopped on a card in the transcript β€” a permission prompt or a question, neither of which can be answered by voice, and whose only other tell is a silence that reads as a hang. Permission mode and both commands live behind the gear; the gear itself turns amber when permissions are anything but auto, because that is the setting which decides how often a spoken conversation can be stopped dead.
  • Commands are detected, never invented: the test and build commands come from what the project already declares, and a repo the detectors do not recognise gets nothing rather than a guess. Name one in the gear (it wins over HARNESS_TEST_CMD/HARNESS_BUILD_CMD, and the panel says which layer is in force) or clear it to hand it back.

Running it

Prerequisites: Node β‰₯ 23 (the harness runs TypeScript natively β€” no build step), and Claude Code installed and logged in β€” the Agent SDK drives the claude binary, and Beth rides its authentication, so if claude works in your terminal, Beth has what it needs. Chrome, if you want voice.

git clone git@github.com:dannybrian/beth.git ~/Sources/beth
cd ~/Sources/beth && pnpm install                      # or npm install
ln -sf ~/Sources/beth/bin/beth.mjs ~/.local/bin/beth   # once
cd <a-project-repo> && beth

Or directly, without port-picking: node src/main.ts β†’ http://localhost:4620.

The three dependencies pnpm install pulls are each deliberate: the Claude Agent SDK, zod, and the ElevenLabs SDK (TTS only, and only used if you configure voice). The UI is dependency-free vanilla DOM over SSE + POST.

Configuration

Config layers, most specific first: real env vars β†’ the bound repo's .env β†’ ~/.director-harness/.env (credentials belong in the machine file). Per-repo state lives in ~/.director-harness/<repo-slug>/; persona state in ~/.director-harness/persona-state/<slug>/. Nothing in this repo holds a key.

There is a fourth layer, and it is the only one that is written: what you type into the page's gear panel is stored in the per-repo state dir and wins over all three β€” the panel says which layer is in force. Only what a page can set lives there (the test and build commands, today); secrets stay in the .env layers.

Env Default Meaning
HARNESS_PORT first free from 4620 In a repo's .env it PINS that repo's port β€” a tailnet mapping needs a port that does not drift with start order
HARNESS_MODEL claude-opus-5-5 Director session model β€” the dominant cost lever. The strip's choice STICKS per repo and wins over this
HARNESS_PERMISSION_MODE auto The SDK permission mode the session starts in
HARNESS_CLAUDE_BIN ~/.local/bin/claude Native CLI (see gotcha below)
HARNESS_DIRECTOR_PLAN β€” The role-lock plan (/director-skills creates one)
HARNESS_PLAN_ROOTS β€” Comma list of plan trees; empty means auto-discovery
HARNESS_NO_KICKOFF β€” Boot silently (cheap for testing)
HARNESS_INBOX β€” Hand-off files to read beside the inbox dir (see The inbox). ⚠ Accumulates across layers
ELEVENLABS_API_KEY β€” Voice, both directions. Needs the Text to Speech permission
HARNESS_VOICE_ID β€” The machine's default voice; personas override
HARNESS_TTS_MODEL eleven_flash_v2_5 ⚠ Flash predates v3 audio tags β€” tags stripped
HARNESS_SPEECH_LEVEL brief How much is read aloud (full, brief, headings, headlines, off)
HARNESS_TTS_USD_PER_1K_CREDITS 0.22 Your plan's credit price, for the estimate
HARNESS_EAR scribe browser opts out of Scribe; keyless harnesses fall back anyway
HARNESS_EAR_VAD_SECS Scribe's own How much silence ends a spoken utterance
HARNESS_STT_USD_PER_HOUR 0.39 Your plan's listening rate, for the meter
HARNESS_KEYTERMS β€” Nouns no file mentions. ⚠ Accumulates across layers
HARNESS_VOICE_EFFORT low Effort while the mic is open (off disables the duck)
HARNESS_VOICE_SETTLE_MS 2500 Browser ear only β€” quiet time before a spoken turn sends
HARNESS_SPEECH_BIASING off Browser ear only β€” Scribe always biases toward project nouns
HARNESS_KEYTERM_BOOST 2 Browser ear only β€” how hard to push, 0–10
HARNESS_CREDITS_MONTHLY β€” Arm the usage-credit countdown with your monthly budget
HARNESS_CREDITS_RESET_DAY 1 Day of month the billing cycle turns over
HARNESS_TEST_CMD detected Test command override β€” ⚠ the gear panel wins over it
HARNESS_BUILD_CMD detected Build command override, same gear caveat. ⚠ Must terminate β€” not a dev server
HARNESS_PERSONAL on off disables remembering the person entirely

Finer knobs (timeouts, settle intervals, the bind address) are enumerated in src/config.ts, which is the authority on all of these.

What's here

Module Owns
session.ts The one long-lived streaming query(); turns; model/effort/permission/persona switches
askgate.ts canUseTool β€” questions pend, everything else becomes an approve/deny card
tools.ts In-process MCP: say, show, workbench, suggest_reply, queue_decision, close_decision, close_inbox, close_worker, pending, plans, speech, remember, recall
toolInput.ts Repairs a tool call written in two formats at once
personas.ts Machine-level directors: reader, per-repo choice, memory seeding
mouth/mouth.ts / speakOut.ts / spoken.ts / audioTags.ts Speech out: a liftable core (held lines, TTS, the bill) and its harness adapter; what is said and excerpted
ear/ / earHost.ts Speech in: the liftable Scribe engine and the harness's one-ear host
voiceRoom.ts Several harnesses, one machine: the talking stick, the mute, the volume
ui/capture.js / ui/remoteEar.js / ui/pcm.js The page half of the ear β€” mic capture, PCM, the Listener-shaped remote
ui/listen.js / ui/speaker.js / ui/wire.js The fallback (browser) ear, the mouth, and the wire panel β€” native ES modules, each tested from node with a stubbed browser object
workIndex.ts / workItems.ts / plansReader.ts The work contract and its built-in reader
inbox.ts The other built-in reader: hand-offs from other agents, addressed by name; the acks, never the producer's file
statusLine.ts The terminal's bottom line β€” where she is, and whether she is thinking; nothing off a TTY
planName.ts ⚠ The one plan-file writer β€” name: on rename, nothing else
pins.ts / handoff.ts Shelf, and terminal handoff
personal.ts / greeting.ts Memory of the person; the boot line and the onboarding offer
testRunner.ts / buildRunner.ts / runCommand.ts The two lights: detect, settle, run, parse failures; the build fired from the strip
settings.ts The gear's store β€” the one config layer the page writes, and it wins
creditMeter.ts The usage-credit countdown, armed only past the plan windows
workbench.ts The pinned bench URL β€” what we're working on, bold at centre top
suggestion.ts The suggested reply β€” ghost text in the composer, Tab to accept; held until her turn ends
directorRole.ts / directorName.ts Shadow vs director; what to call the director
server.ts / bus.ts / eventlog.ts / state.ts / origin.ts Transport, replay, events, queues, and the Origin check on API writes
wireTap.ts The compact record of every SDK message the wire panel pulls
keyterms.ts / links.ts / markdown.ts / activity.ts Vocabulary, file links as offsets, span overlays, activity lines
showImage.ts Proving an image path before /api/image serves it or show renders it

docs/ holds design records β€” the reasoning behind the voice plane, the ear, the status surface, personal context, the plans panel, the inbox, /director-skills, and the desk (agreed, unbuilt: one page over several running directors) β€” written so a fresh session can pick the work up without the conversation that produced it.

Machine gotcha

My default node is x64 under Rosetta, so the SDK's bundled Bun CLI hangs silently ("CPU lacks AVX support" on stderr is the only tell). Every session passes pathToClaudeCodeExecutable pointing at the native arm64 install β€” HARNESS_CLAUDE_BIN if yours lives elsewhere.

The name

Beth is lovingly named after my grandmother, Beth Brian. It would be proud.

About

A conversational harness for director agents, using Claude Code SDK and ElevenLabs voices.

Resources

Stars

3 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages