A plugin-oriented Codex-powered agent service.
Project description
Nyanpasu
Nyanpasu is a plugin-oriented Codex agent service. The core runtime is deliberately generic: it accepts events from plugins, turns them into AgentTask objects, prepares one reusable workspace per context, reuses persistent Codex threads per context, records state in SQLite, and runs Codex under a constrained runtime policy.
GitHub PR review is implemented by the nyanpasu-github-reviewer plugin, not by the core package.
Core Responsibilities
- Async task execution with per-context serialization and bounded concurrency.
- Context workspace management. By default, one
context_keyowns one reusable worktree that is reset to the task revision before each run. - Optional event snapshots for plugins that explicitly need per-event isolation.
- Persistent task, thread, and context state.
- Codex backend management through
codex app-serverorcodex exec. - Plugin lifecycle hooks, HTTP router registration, and post-process hooks.
- Runtime safety defaults:
sandbox = "workspace-write"andapproval_policy = "never".
Anything domain-specific belongs in a plugin. GitHub event parsing, polling, webhook signatures, gh-llm prompts, and review submission live in packages/nyanpasu-github-reviewer.
Configuration
Nyanpasu uses TOML and Pydantic models. Core config lives at the top level; plugin config lives under plugins.<plugin_id>.
Nyanpasu has one user-facing home directory. Set NYANPASU_HOME to choose it; otherwise it defaults to ~/.nyanpasu. Config is always read from $NYANPASU_HOME/config.toml, and runtime state, logs, SQLite, and managed worktrees also live under $NYANPASU_HOME.
state_dir is intentionally not a TOML option. To move both config and state, move NYANPASU_HOME.
enabled_plugins = ["github_reviewer"]
[server]
host = "127.0.0.1"
port = 8765
[codex]
backend = "app-server"
sandbox = "workspace-write"
approval_policy = "never"
command_timeout_seconds = 3600
[runtime]
concurrency = 4
coalesce_window_seconds = 600
clean_event_snapshots = true
[plugins.github_reviewer]
github_login = "your-github-login"
poll_interval_seconds = 600
poll_event_pages = 3
poll_max_events_per_cycle = 0
review_language = "Chinese"
[[plugins.github_reviewer.instruction_docs]]
name = "SOUL.md"
path = "/path/to/SOUL.md"
[plugins.github_reviewer.repos."owner/repo"]
local_path = "/path/to/repo"
github_remote = "https://github.com/owner/repo.git"
base_branches = ["main"]
[[plugins.github_reviewer.repos."owner/repo".instruction_docs]]
name = "AGENTS.md"
path = "/path/to/repo/AGENTS.md"
required = false
Instruction documents are task-scoped. A plugin can attach files such as SOUL.md, AGENTS.md, or project policy notes to an AgentTask; the core runtime appends them only for that task before invoking Codex. They are not global Nyanpasu identity and are not hardcoded into the core or GitHub reviewer prompt.
Run
Create $NYANPASU_HOME/config.toml from examples/config.toml, then start the agent service:
export NYANPASU_HOME="$HOME/.nyanpasu"
uv run nyanpasu serve
Inspect runtime state:
uv run nyanpasu status
curl http://127.0.0.1:8765/tasks
curl http://127.0.0.1:8765/contexts
The GitHub reviewer plugin mounts its webhook at:
POST /plugins/github-reviewer/webhook
The plugin can also start its poller during plugin setup. Events poll uses GitHub repository events as the source of truth: the first poll records the current repo event cursor without handling older events, later polls process matching events after that cursor, and already processed delivery ids are skipped. poll_max_events_per_cycle = 0 means process every matching event in the poll window; set it to a positive number only when you intentionally want a per-cycle cap.
Plugin Contract
A plugin exposes a NyanpasuPlugin through the nyanpasu.plugins entry point group.
class MyPlugin:
id = "my_plugin"
config_model = MyPluginConfig
async def setup(self, runtime, config):
runtime.add_router(router, prefix="/plugins/my-plugin")
runtime.add_post_process_hook(self.id, self.after_task)
await runtime.submit(task)
async def shutdown(self):
...
Plugins send work to the core by creating AgentTask:
AgentTask(
task_id="event-123",
action=TaskAction.RUN,
context_key="my-domain:object-456",
prompt="Review or handle this event.",
instruction_docs=[
InstructionDocument(
name="AGENTS.md",
source="/path/to/repo/AGENTS.md",
content="Follow this repository's local conventions.",
),
],
workspace=WorkspaceRef(
key="owner/repo",
local_path=Path("/path/to/repo"),
remote="https://github.com/owner/repo.git",
ref="pull/123/head",
revision="abc123",
),
dedupe_key="event-123",
metadata={"plugin_id": "my_plugin"},
)
Core executes the task and calls post-process hooks registered for metadata["plugin_id"].
By default, the task uses workspace_policy = "context": Nyanpasu resets the context worktree to workspace.revision or workspace.ref, runs Codex there, and keeps that workspace for the next event in the same context. Plugins can opt into workspace_policy = "event_snapshot" only when they need a disposable per-event worktree.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nyanpasu-0.1.0.tar.gz.
File metadata
- Download URL: nyanpasu-0.1.0.tar.gz
- Upload date:
- Size: 19.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
835c9c289d821e5ca47f568d2c9cbb99e06bc96b8632c966a3eb0ee796836b76
|
|
| MD5 |
3c495cc428ea30d88526408815451e6e
|
|
| BLAKE2b-256 |
791075f33a6e595e2713504880f557be078374d56580eb0fa27ffd85e2c901dc
|
Provenance
The following attestation bundles were made for nyanpasu-0.1.0.tar.gz:
Publisher:
release.yml on ShigureLab/nyanpasu
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nyanpasu-0.1.0.tar.gz -
Subject digest:
835c9c289d821e5ca47f568d2c9cbb99e06bc96b8632c966a3eb0ee796836b76 - Sigstore transparency entry: 1678665317
- Sigstore integration time:
-
Permalink:
ShigureLab/nyanpasu@8c969a5a2f92b07f2d64c93fc7f39c6c3766922f -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/ShigureLab
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@8c969a5a2f92b07f2d64c93fc7f39c6c3766922f -
Trigger Event:
push
-
Statement type:
File details
Details for the file nyanpasu-0.1.0-py3-none-any.whl.
File metadata
- Download URL: nyanpasu-0.1.0-py3-none-any.whl
- Upload date:
- Size: 24.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2be6f9a4a3522ea5eba65144fb5cddf8bba5004736c2847a126f09e6912e2dd3
|
|
| MD5 |
60577649abd7c648295055f68ce0b30e
|
|
| BLAKE2b-256 |
3fb6bc304d363cb507887a0bd55a573efa084bc8fe5ec8d98f3b1f845ec6399f
|
Provenance
The following attestation bundles were made for nyanpasu-0.1.0-py3-none-any.whl:
Publisher:
release.yml on ShigureLab/nyanpasu
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nyanpasu-0.1.0-py3-none-any.whl -
Subject digest:
2be6f9a4a3522ea5eba65144fb5cddf8bba5004736c2847a126f09e6912e2dd3 - Sigstore transparency entry: 1678665433
- Sigstore integration time:
-
Permalink:
ShigureLab/nyanpasu@8c969a5a2f92b07f2d64c93fc7f39c6c3766922f -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/ShigureLab
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@8c969a5a2f92b07f2d64c93fc7f39c6c3766922f -
Trigger Event:
push
-
Statement type: