Skip to main content

plugin-platform

The plugin platform, always on: third-party plugin code runs isolated in the plugin runner, reaches RedAmon only through the Gateway, and changes agent behaviour only through text a person approved in core UI. The base repository holds no plugin logic, and a host that cannot run the platform is refused, never half-started. Trigger: editing webapp/src/lib/plugins/, webapp/src/app/api/plugins/, webapp/src/app/api/plugin-gateway/, webapp/src/app/api/plugin-runner/, webapp/src/app/api/internal/plugins/, webapp/src/components/plugins/, webapp/src/app/plugins/, services/plugin_runner/, agentic/plugin_api.py, agentic/prompts/skill_part_seam.py, docker-compose.plugins.yml, the plugin-runner or plugin-gateway services, or a _plugins_* / plugins_* function in redamon.sh.

소스 정보

저장소
samugit83/redamon
최근 소스 활동
2026년 10월 14일 13:09
감지된 SKILL.md 언어
영어
스타
3,106
포크
646

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
plugin-platform
description
The plugin platform, always on: third-party plugin code runs isolated in the plugin runner, reaches RedAmon only through the Gateway, and changes agent behaviour only through text a person approved in core UI. The base repository holds no plugin logic, and a host that cannot run the platform is refused, never half-started. Trigger: editing webapp/src/lib/plugins/, webapp/src/app/api/plugins/, webapp/src/app/api/plugin-gateway/, webapp/src/app/api/plugin-runner/, webapp/src/app/api/internal/plugins/, webapp/src/components/plugins/, webapp/src/app/plugins/, services/plugin_runner/, agentic/plugin_api.py, agentic/prompts/skill_part_seam.py, docker-compose.plugins.yml, the plugin-runner or plugin-gateway services, or a _plugins_* / plugins_* function in redamon.sh.
license
MIT
metadata
{"author":"redamon","version":"1.0.0","scope":["root","webapp","agentic"],"auto_invoke":["Editing the plugin platform: the plugins lib or routes, the plugin runner, or the Gateway","Changing how plugin services, networks or the plugins overlay are started by redamon.sh or compose"]}
## When to Use - Changing the Plugin Manager, the catalog check, the Gateway, the override store or the UI host. - Changing the runner, its worker spawn, the SDK or the `plugin-gateway` proxy. - Touching how `redamon.sh` or compose start, remove or wire the plugin services. For a new built-in skill part also follow `builtin-agent-skill` (layer 10, the part registry); for an LLM call path, `llm-provider-integration`; for tests, `redamon-testing`. --- ## Critical Rules - **NEVER put plugin-specific logic in the base repository.** No plugin id, prompt or behaviour in `webapp/src`, `agentic` or `services`; a plugin's name may appear only in tests, fixtures and docs. Check: `grep -rnw -i "skiller" --include=*.ts --include=*.tsx --include=*.py webapp/src agentic services` finds only test files (`-w`, or every `UserSkillError` matches). The platform is generic; a plugin lives in `redamon-plugins`. - **NEVER add an off switch or a degrade-to-off path.** The platform always runs (owner decision 2026-10-12). A host that cannot run it is refused by install, update and up with the cause named, before any core service is recreated (`require_plugin_engine`, `plugins_preflight`, `_plugins_prepare` in [redamon.sh](../../redamon.sh)); a runner that is down at runtime is a state the UI shows (the runner banner, 503 `runner_unavailable`), never a 404. - **NEVER name a plugin service in a plain `up`.** `docker compose up -d --no-deps <profile service>` starts a profile service even without `--profile` (measured, experiment E8), so a plugin service in `rebuild_core`, `restart_only` or any ad-hoc `up` starts it without the recreate a runner rebuild needs and without the failure that stops the command. Only `plugins_converge` starts `plugin-runner` and `plugin-gateway`. - **NEVER wire the webapp to the plugins in `docker-compose.yml`.** Its `plugins-edge` network and `plugins` volume live in [docker-compose.plugins.yml](../../docker-compose.plugins.yml), which `redamon.sh` loads only after the plugin preflight created the plugin networks, so a Docker that refuses them stops the command with that cause instead of failing halfway through the core `up`. A new webapp plugin variable still goes in the webapp's `environment:` list: the webapp has no `env_file`. - **NEVER put the runner or the proxy on `redamon`, and never widen the proxy's prefixes.** Postgres, Neo4j, kali-sandbox and agent routes there trust the network. The proxy passes only `/api/plugin-gateway/v1/*`, `/api/plugin-runner/v1/*` and `/runner/v1/*` ([proxy.py](../../services/plugin_runner/gateway_proxy/proxy.py)); `tests/redamon_plugins_profile_test.sh` asserts the networks. - **ALWAYS serve a Gateway call through `withGateway`** ([gateway.ts](../../webapp/src/lib/plugins/gateway.ts)). It re-authorizes every call: the call token, `action_ended`/`job_ended` (a token must not outlive its action or job; found by the phase 04 review), the plugin still serving (enabled, ready, not revoked), the permission an admin granted, and the tenancy of the session. A route that reads the token itself skips some of these. - **NEVER let a plugin write what the agent runs.** A plugin may only `propose`; approval, reset and deletion are core routes that check the scope owner strictly ([changeSetAccess.ts](../../webapp/src/lib/plugins/changeSetAccess.ts): `ownsScope`, and `bodyOwnerMatches` because the act-as cookie is site-wide), and admin lifecycle routes re-read the role from the database because the session JWT outlives a demotion ([lifecycleRoutes.ts](../../webapp/src/lib/plugins/lifecycleRoutes.ts)). A `reviewProposal` that a job reports is validated in [jobs/complete](../../webapp/src/app/api/plugin-gateway/v1/jobs/complete/route.ts) like a sync result, never trusted. - **NEVER deliver approved text outside the agent's own settings fetch.** `skillTextOverrides` goes only to the master internal key with `includeSkillOverrides=true` ([projects/[id]/route.ts](../../webapp/src/app/api/projects/[id]/route.ts)): `includeSkillContent` alone is also sent by text-to-cypher and accepted from the scanner key. On the agent side the seam reads only the session's settings context and falls back to the factory text ([skill_part_seam.py](../../agentic/prompts/skill_part_seam.py)); it never raises. The one exception is `user_skill.text`: approving never makes it active, it saves a NEW user skill (`adopted`), which is the person's own and travels the ordinary user-skill path (`userAttackSkills` with `includeSkillContent`, which the scanner key can read too). Never deliver a `user_skill.text` row's value any other way. - **ALWAYS gate saving a `user_skill.text` proposal on the proposer** (enabled, ready, not revoked, granted `override:user_skill.text`, and `activeVersion === meta.pluginVersion`) in the save transaction, failing closed ([userSkillAdoption.ts](../../webapp/src/lib/plugins/userSkillAdoption.ts)). What a save creates outlives the plugin, so the catalog's revocation must reach it: reconcile withdraws the revoked version's waiting proposals and quarantines the skills saved from them, installed or not ([userSkillRevocation.ts](../../webapp/src/lib/plugins/userSkillRevocation.ts)), and every toggle writer refuses `true` on a quarantined skill. - **NEVER hand a plugin a user skill outside its session or holding credentials.** The Gateway's `user_skill.text` target ([userSkillOverrideOps.ts](../../webapp/src/lib/plugins/userSkillOverrideOps.ts)) requires the token's user as owner, a session whose turns used the skill ([sessionSkills.ts](../../webapp/src/lib/plugins/sessionSkills.ts)) and no quarantine, answers every refusal with the same 404 (no existence oracle), and refuses credential-shaped text with 422 `skill_contains_credentials`. The platform's meta keys (`PLATFORM_META_KEYS` in [overrides.ts](../../webapp/src/lib/plugins/overrides.ts)) are stripped from a plugin's meta; the proposer's version, conversation and job come from the call token. - **ALWAYS read time from `clock.ts` and never import the test doubles from production code.** [clock.ts](../../webapp/src/lib/plugins/clock.ts) is the only clock, so tests pin it; [noProductionImports.test.ts](../../webapp/src/lib/plugins/__testing__/noProductionImports.test.ts) fails when a production module imports `webapp/src/lib/plugins/__testing__/`. - **A new extension point, SDK call or UI primitive is a platform version bump** held equal in five files by `platformVersion.parity.test.ts` (the runner's contract cases included). Follow the checklist in [README.DEV.md §6.6](../../docs/readmes/README.DEV.md#66-adding-a-plugin-extension-point). --- ## Commands ```bash cd webapp && npx vitest run --no-file-parallelism src/lib/plugins src/components/plugins src/app/api/plugins src/app/plugins cd webapp && npm run plugins:schemas # regenerate schemas/json after a schema change docker compose --profile plugins build plugin-runner # before the plugin_runner test section ./redamon.sh test unit # includes plugin_runner, shell and vitest bash tests/redamon_plugins_lifecycle_test.sh # install/update/up and every refusal, stubbed docker bash tests/plugins_isolation_live.sh # live: needs ./redamon.sh up ``` --- ## Resources - [docs/readmes/README.PLUGINS.md](../../docs/readmes/README.PLUGINS.md) - design, lifecycle, trust model - [docs/readmes/README.PLUGIN_SDK.md](../../docs/readmes/README.PLUGIN_SDK.md) - the plugin author's contract - [docs/readmes/README.TESTING.md](../../docs/readmes/README.TESTING.md) - "The plugin platform" test map - Related skills: `builtin-agent-skill`, `llm-provider-integration`, `redamon-testing`
GitHub에서 보기