> ## Documentation Index
> Fetch the complete documentation index at: https://docs.asymptotelabs.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Senpi

> Asymptote support details for the Senpi standalone edition of oh-my-openagent

## Runtime overview

Asymptote supports [Senpi](https://github.com/code-yeongyu/senpi), the standalone edition of [oh-my-openagent](https://github.com/code-yeongyu/oh-my-openagent) (OMO), through a managed local extension.

<Note>
  oh-my-openagent ships three editions. **Ultimate** is a plugin riding [OpenCode](/runtimes/opencode); **Light** is a plugin riding [Codex CLI](/runtimes/codex-cli); both already flow through Asymptote's existing OpenCode and Codex CLI integrations, so no separate work is needed for them. **Senpi** is the one edition with no host of its own: an [in-flight fork of pi-mono](https://github.com/badlogic/pi-mono) that OMO brands and bundles its own extension into, distributed as the `omo` command. This page covers that edition only.
</Note>

Senpi is a hard fork of pi-mono, as [Pi](/runtimes/pi), [Oh My Pi](/runtimes/oh-my-pi), and [Prime Agent](/runtimes/prime-agent) are. All four are supported separately and recorded under their own harness names, because they are separately installed products that one machine can run side by side.

Senpi fits neither of Asymptote's two usual integration shapes. It has no hooks configuration file to merge a managed hook block into, and no OpenTelemetry export to point at the local collector. Its documented observation surface is the TypeScript extension API it inherited from Pi, so the integration is extension-shaped: one Asymptote-owned extension file forwards runtime events to `beacon-hooks`, the same shape as the [Pi](/runtimes/pi), [Oh My Pi](/runtimes/oh-my-pi), [Prime Agent](/runtimes/prime-agent), [OpenCode](/runtimes/opencode) and [Cline](/runtimes/cline) integrations.

```bash theme={null}
beacon endpoint hooks install --harness omo
```

## Kept pi-mono's tool set

Unlike Prime Agent, which routes essentially everything through a single Python kernel, Senpi kept pi-mono's ordinary built-in tools — `bash`, `read`, `edit`, `write`, `grep`, `find`, and `ls` — alongside its own additions. So its telemetry shape looks like Pi's and Oh My Pi's rather than Prime Agent's: a shell command is `command.executed` with a real command line, an edit is `file.modified` with the unified patch, and a read is `file.read`.

Senpi's own ExtensionEvent surface is larger than Pi's — it adds `tool_execution_start`/`tool_execution_end` for execution progress, `turn_start`/`turn_end` for turn bookkeeping, `agent_start`/`agent_end`/`agent_settled`, `model_select`, and more — but none of those describe a new kind of agent action that `tool_call`/`tool_result` do not already cover, so the managed extension leaves them unsubscribed for the same reason it ignores streaming and provider internals on every other pi-mono fork.

## Prerequisites

Before enabling Senpi telemetry, make sure:

* Senpi's `omo` edition is installed (`bun add -g omo-ai@beta`) and available as the `omo` executable, or has a local state directory at `~/.omo/agent`.
* `beacon endpoint install` has run so shared endpoint config and runtime log paths exist.
* Senpi is restarted after install or removal so new sessions load the updated extension.

## Collection path

Asymptote's managed Senpi extension is a single TypeScript file at one of two auto-discovered extension locations:

| Level   | Extension path                      |
| ------- | ----------------------------------- |
| User    | `~/.omo/agent/extensions/beacon.ts` |
| Project | `./.omo/agent/extensions/beacon.ts` |

User level is the default, because it follows the operator rather than one checkout. `beacon endpoint discover` reports on the user path only, so a project-level extension does not appear in discovery output.

<Warning>
  The project path keeps the `agent` segment, the same shape [Prime Agent](/runtimes/prime-agent) uses. Senpi's config directory name for this brand is `.omo`, and its own directory resolver joins the `agent` segment under the working directory just as it does under the home directory — where [Pi](/runtimes/pi) uses `.pi/extensions` and [Oh My Pi](/runtimes/oh-my-pi) uses `.omp/extensions` at project scope. A file written to `./.omo/extensions/` is never loaded.
</Warning>

`OMO_CODING_AGENT_DIR` replaces the user-level agent directory outright, and Asymptote honors it — including a leading `~`, which the runtime expands before use. When it is unset, Asymptote falls back to `SENPI_CODING_AGENT_DIR` and then `PI_CODING_AGENT_DIR`, the same two legacy prefixes Senpi's own brand profile keeps readable: `SENPI` is the upstream engine's own name, and `PI` is pi-mono's. None of the three moves the project path, because Senpi does not consult any of them there.

Asymptote identifies its own extension file by the marker `beacon-managed-omo-extension:v1`. The version suffix is part of the contract with the extension source: it is what lets a repair recognize a stale file instead of leaving it in place. A `beacon.ts` without the marker belongs to somebody else, so install will not overwrite it and discovery does not report it as Asymptote telemetry. The marker is distinct from Pi's, Oh My Pi's, and Prime Agent's, so a file found at any of the four paths is attributed to the runtime that actually loads it.

Senpi has no OpenTelemetry export for Asymptote to configure, so there is no OTLP path for this runtime.

## Discovery and status

Asymptote detects Senpi through the `omo` executable, and treats the `~/.omo/agent` state directory as an additional signal. Senpi installed through npm into a directory this process did not inherit on `PATH` is not visible as an executable, because a shell alias, a version manager, or a per-project install can all hide it while the state directory is still present. The Pi, Oh My Pi, Prime Agent, OpenCode, Cursor, and Hermes probes use the same fallback.

`senpi` is deliberately not probed for. It is the upstream engine's own binary name, and a machine can have plain, un-OMO'd Senpi installed without oh-my-openagent at all — probing for it here would claim an install this integration did not verify.

```bash title="Show Senpi discovery state" theme={null}
beacon endpoint discover --all --json
```

Senpi reports as the `omo_senpi` harness with capability `plugin`:

| Telemetry status | Meaning                                                                                                       |
| ---------------- | ------------------------------------------------------------------------------------------------------------- |
| `missing`        | No extension file at the user-level managed path                                                              |
| `disabled`       | A `beacon.ts` exists but carries no Asymptote marker, so it is somebody else's extension sharing the filename |
| `enabled`        | Asymptote's managed extension is in place                                                                     |

An unmarked extension file reports `disabled` rather than `enabled`, because reporting it as enabled would show the runtime as covered while no events arrive.

## Install or configuration support

`beacon endpoint install` prepares shared endpoint config and runtime log paths. The extension is installed separately, because Senpi loads it from the user's own profile rather than from a machine-wide location:

```bash theme={null}
beacon endpoint hooks install --harness omo            # user level (default)
beacon endpoint hooks install --harness omo --level project
beacon endpoint hooks status --harness omo
beacon endpoint hooks uninstall --harness omo
```

`omo`, `omo_senpi`, and `omo-senpi` all resolve to this runtime. Bare `senpi` and `oh-my-openagent` are deliberately not accepted: plain Senpi is a separately installable engine you can run without OMO at all, and `oh-my-openagent` also names OMO's OpenCode and Codex CLI editions, which install through the existing OpenCode and hook-config paths rather than through this extension. Accepting either spelling here would claim a name that belongs to a different install.

Install writes one file and refuses to touch a `beacon.ts` it did not write, so an extension of your own that happens to share the filename is left alone and the install fails loudly rather than replacing it. Uninstall removes only a file carrying this runtime's marker.

`status` reports `installed=false` when the extension exists but points at a hook binary that is no longer there, which happens after a Beacon uninstall, a partly applied update, or a home directory restored onto a different machine. In each case Senpi loads an extension that spawns nothing.

## Telemetry coverage

| Area                                             | Support                                                                                                                                                           |
| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Runtime discovery                                | Supported through executable and `~/.omo/agent` detection, managed extension path, and telemetry status                                                           |
| Harness attribution                              | Supported. `omo`, `omo_senpi`, and `omo-senpi` all normalize to `omo_senpi`                                                                                       |
| Extension install, status, uninstall, and repair | Supported                                                                                                                                                         |
| Session lifecycle                                | Supported. `session.started` and `session.ended`, carrying why the session started or stopped — a fork and a resume both produce a session with history behind it |
| Prompts                                          | Supported. `prompt.submitted`, with whether the input was typed, delivered over RPC, or injected by another extension                                             |
| Tool use                                         | Supported. `tool.invoked` before execution, then `tool.completed` or `tool.failed`                                                                                |
| Commands                                         | Supported. `command.executed` for the `bash` tool and for commands you run with the `!` prefix, which are marked as operator-initiated                            |
| File activity                                    | Supported. `file.read`, `file.created`, and `file.modified` for the `read`, `write`, and `edit` tools, the last carrying the unified patch                        |
| Agent reasoning                                  | Supported. `agent.reasoning` from an assistant message's thinking parts, in the OTel GenAI reasoning-part shape                                                   |
| Token usage and cost                             | Supported. `token.usage` normalized into `gen_ai.usage`, including cache and reasoning tokens and runtime-reported cost                                           |
| Approval decisions                               | Not available. Senpi exposes no operator approval decision through its extension API. See [Known gaps](#known-gaps)                                               |
| Local JSONL and dashboard                        | Supported                                                                                                                                                         |
| MDM deployment                                   | Supported for the endpoint agent. The Senpi extension installs separately in the logged-in user's context                                                         |

Harness names are matched against a closed set of spellings rather than by substring. `omo` is an ordinary three-letter string that could appear inside an unrelated harness attribute, so a substring rule would misattribute sessions that are not Senpi's.

## Data handling

Senpi content is handled like every other runtime. Prompts, command lines, command output, tool arguments, paths, diffs, and reasoning text are retained in local or customer-controlled logs, with local secret redaction and per-string limits applied before writing, and a hash and byte count on each content-bearing event. Events over the 64 KiB limit drop raw and retained content, preserve stable metadata, and set `field_truncated`.

The extension itself sends nothing over the network. It spawns the local `beacon-hooks` binary with a fixed argv and writes the event to its stdin. A send that has not completed in two seconds is abandoned so Beacon cannot stall Senpi's agent loop, and a failure to spawn costs the event rather than the run.

Senpi's own telemetry — the anonymous, PostHog-backed "OmO Native" analytics pipeline documented in its `senpi-telemetry.md` — is unrelated to this integration. It reports only aggregated buckets and counters with no raw content, and Asymptote neither reads from it nor writes to it.

## Known gaps

* **No approval telemetry.** Senpi's `tool_call` event lets an extension block a call, but that is an extension deciding rather than an operator being asked. Its own permission-system builtin owns the real approval prompt without publishing it as an extension event, so Beacon records these as tool activity and writes no approval events. [Pi](/runtimes/pi) and [Prime Agent](/runtimes/prime-agent) work the same way for the same reason; [Oh My Pi](/runtimes/oh-my-pi) is the fork that does report real ones. Detections in `rules/approval-abuse/` do not fire on Senpi activity.
* **No enforcement.** As with every other runtime, enforcement stays behind the optional, off-by-default policy provider seam (`BEACON_POLICY_PROVIDER`), which is not wired to Senpi.
* **Streaming and progress events are not collected.** The extension subscribes to seven of Senpi's event types and ignores the rest — provider request and response internals, streaming message and tool-execution updates, turn bookkeeping, compaction, model-select, and TUI plumbing. Assistant output is recorded once when a message finalizes rather than token by token, so Beacon stays out of the streaming path.
* **The OpenCode and Codex CLI editions are out of scope for this page.** They ride the existing [OpenCode](/runtimes/opencode) and [Codex CLI](/runtimes/codex-cli) integrations rather than this extension, and are not separately attributed as `omo`-branded sessions today.

## Deployment notes

The extension is loaded when Senpi starts, so an install taken while it is running takes effect on the next launch.

Confirm discovery sees the runtime, then generate one Senpi event and check the log:

```bash theme={null}
/opt/beacon/bin/beacon endpoint discover --all --json
/opt/beacon/bin/beacon endpoint hooks status --harness omo
/opt/beacon/bin/beacon endpoint doctor --system
grep '"name":"omo_senpi"' ~/.beacon/endpoint/logs/runtime.jsonl | tail -3
```

## Related

<Columns cols={3}>
  <Card title="Pi" icon="code" href="/runtimes/pi">
    The upstream runtime Senpi forked, supported through the same extension shape.
  </Card>

  <Card title="Prime Agent" icon="code" href="/runtimes/prime-agent">
    Another pi-mono fork, this one routing everything through a single Python kernel.
  </Card>

  <Card title="Supported agent harnesses" icon="list-check" href="/runtimes">
    Return to the runtime support overview.
  </Card>
</Columns>
