OmniAgent Delivery — Deployment, Discord, and Gateway Hardening — Roadmap¶
Initiative: INIT-OMNIAGENT-001
Repository: github.com/plexusone/omniagent
Status: Executing — 21 of 30 items completed
RMI IDs are stable and permanent. Commits implementing an item carry the trailer
Refs: RMI-OMNIAGENT-<NNN>. Phase status is derived from member RMIs — a phase is complete only when all its required RMIs are complete.
Phase 1 — Cloud Deployment¶
Theme: Ship OmniAgent as a Discord bot on AWS Lightsail via omnideploy from a public GHCR image. Status: In progress — 2 of 5 items completed
- [x]
RMI-OMNIAGENT-001Discord 2000-character message chunking in omnichat -
- Acceptance: replies over 2000 chars split into multiple messages; rune-based, breaks on paragraph/newline/space; shipped as omnichat v0.8.1 and linked into the omniagent binary
- [x]
RMI-OMNIAGENT-002Standalone multi-stage Dockerfile for omniagent -
- Acceptance:
docker build --platform linux/amd64succeeds with no local replace mounts; runsgateway run; serves/health
- Acceptance:
- [x]
RMI-OMNIAGENT-003Publish container image to GHCR (public) - Depends on:
RMI-OMNIAGENT-002 -
- Shipped:
.github/workflows/docker.yamlbuilds and pushesghcr.io/plexusone/omniagentonv*tag push (:vX.Y.Z,:X.Y,:latest), or:smokevia manualworkflow_dispatch.docs/guides/deployment.mdcorrected to describe the actual tag-triggered behavior instead of "any push." One manual one-time step remains outside CI's reach: an admin must set the GHCR package visibility to Public after the first push (already documented in the guide's "GHCR Authentication" section) —GITHUB_TOKENcan't do this itself.
- Shipped:
- [ ]
RMI-OMNIAGENT-004Lightsail deployment via omnideploy - Depends on:
RMI-OMNIAGENT-003 -
- Acceptance:
omnideploy up --target lightsail --backend pulumiprovisions a running service with the Discord/agent/Serper env
- Acceptance:
-
- Prep done, not yet run (needs AWS credentials this session doesn't have):
deploy/lightsail/deploy.yamlwritten for theomnideploy"omniagent" runtime adapter. Also fixed the Dockerfile'sENTRYPOINT/CMDsplit — LightSail'scommandfield maps to DockerCMD(appended toENTRYPOINT, not a replacement), so the adapter's hardcodedArgs: ["gateway", "run"]would have doubled up against an all-in-ENTRYPOINTimage. Three bugs found and fixed inomnideployitself while verifying this against its actual source (not just its docs):${VAR}/${VAR:-default}expansion was documented but never implemented anywhere in the module (bfea43f); adapter auto-detection iterated a Go map in nondeterministic order, so an ambiguously-named config could resolve to the wrong adapter from run to run (04040a7); andagent.api_key: ${VAR}converts to aSecretRefthe Lightsail/Pulumi backend never actually reads (still open — this is exactlyRMI-OMNIAGENT-006's scope), worked around here by setting secrets viadeploy.environmentdirectly instead.
- Prep done, not yet run (needs AWS credentials this session doesn't have):
- [ ]
RMI-OMNIAGENT-005Deployment smoke test on Lightsail - Depends on:
RMI-OMNIAGENT-004 -
- Acceptance:
/healthgreen; a Discord message triggers a chunked reply;web_search(Serper) returns current results
- Acceptance:
Phase 2 — Deployment Hardening¶
Theme: Make the deployment production-safe: secrets, durable storage, and CI-buildable images. Status: In progress — 2 of 5 items completed
- [ ]
RMI-OMNIAGENT-006SSM-backed secret injection in omnideploy Lightsail target -
- Acceptance:
SecretRef(ssm:/secretsmanager:) resolved and injected; secrets never land in plaintext env or Pulumi state (schema exists; target does not yet consumecfg.Secrets)
- Acceptance:
- [x]
RMI-OMNIAGENT-007Durable session/cron storage on Lightsail -
- Acceptance: session and cron state survive a redeploy (Lightsail Container Service has no volumes; SQLite at
STORAGE_PATHis ephemeral)
- Acceptance: session and cron state survive a redeploy (Lightsail Container Service has no volumes; SQLite at
-
- Shipped: config-driven
storage.type(sqlite/redis/memory) +sessions.enabled/sessions.ttl, matching the surfacedocs/reference/configuration.mdhad documented as "planned";gateway runnow builds the backend and wiresagent.WithStorage/WithSessionStorefor every agent, andagent.WithCronScheduler()for the single-agent path (multi-agent mode skips it — one shared job store, one scheduler, avoids duplicate firing). Also fixed a real gap found in the process:gateway/handlers.go's Discord/WebSocket chat path called the statelessProcessunconditionally despite a "conversation continuity" comment — it now dispatches toProcessWithSessionvia a newgateway.SessionAwareProcessorcapability check whenever a session store is configured, so persisted history is actually used, not just stored.
- Shipped: config-driven
- [x]
RMI-OMNIAGENT-008Single-replica gateway guard -
- Acceptance: gateway mode enforces or documents
replicas == 1(one Discord WebSocket; extra replicas double-answer)
- Acceptance: gateway mode enforces or documents
- [x]
RMI-OMNIAGENT-009Graceful shutdown on SIGINT/SIGTERM -
- Acceptance: signal handler cancels context and runs
router.DisconnectAllon shutdown (implemented incmd/omniagent/commands/gateway.go)
- Acceptance: signal handler cancels context and runs
- [ ]
RMI-OMNIAGENT-010CI-buildable grokify-omniagent image -
- Acceptance: grokify-omniagent builds in CI without local
replacemounts (vendor or publish the 11 replaced deps)
- Acceptance: grokify-omniagent builds in CI without local
Phase 3 — Discord Channel Completeness¶
Theme: Close the documented-but-unimplemented Discord gaps (work lands in omnichat/providers/discord). Status: Planned — 0 of 5 items completed
- [ ]
RMI-OMNIAGENT-011Discord media send -
- Acceptance:
Sendbuildsdiscordgo.MessageSendFiles/EmbedsfromOutgoingMessage.Media(currently onlyContentis set)
- Acceptance:
- [ ]
RMI-OMNIAGENT-012Discord media receive -
- Acceptance:
convertIncomingmapsm.AttachmentstoIncomingMessage.Media
- Acceptance:
- [ ]
RMI-OMNIAGENT-013Discord slash commands -
- Acceptance:
ApplicationCommandregistration +InteractionCreatehandler
- Acceptance:
- [ ]
RMI-OMNIAGENT-014Discord HTTP interactions with Ed25519 verification -
- Acceptance: webhook endpoint verifies
X-Signature-Ed25519; usable as an alternative to gateway mode
- Acceptance: webhook endpoint verifies
- [ ]
RMI-OMNIAGENT-015guildID enforcement and message events -
- Acceptance: configured
guildIDis enforced (currently stored but unused); reaction/edit/delete events mapped
- Acceptance: configured
Phase 4 — Gateway Security and Observability¶
Theme: Harden the gateway control plane and add production observability. Status: Complete — 5 of 5 items completed
- [x]
RMI-OMNIAGENT-016WebSocket origin checking -
- Acceptance:
CheckOriginenforces an allowlist (currently returnstruewith a// TODOingateway/gateway.go)
- Acceptance:
- [x]
RMI-OMNIAGENT-017Gateway WebSocket authentication -
- Acceptance: real auth on
/ws(thehandleAuthhandler currently accepts all requests via a// TODOstub)
- Acceptance: real auth on
- [x]
RMI-OMNIAGENT-018Per-sender rate limiting -
- Acceptance: message-processing path rate-limits per sender/channel
- [x]
RMI-OMNIAGENT-019Observability tracing hook -
- Acceptance:
ObservabilityHook(omniobserve/llmops) applied to the agent ingateway run; slog/langfuse providers available (Opik provider is a follow-on)
- Acceptance:
- [x]
RMI-OMNIAGENT-020Prometheus metrics endpoint -
- Acceptance:
/metricsexposes gateway/agent metrics for scraping
- Acceptance:
Phase 5 — Test Coverage¶
Theme: Increase test coverage for critical low-coverage packages. Status: Complete — 5 of 5 items completed
- [x]
RMI-OMNIAGENT-021Agent package test coverage (target: 50%+) -
- Acceptance:
agentpackage coverage increases from 7% to 50%+; covers core Process flow, tool execution, session handling
- Acceptance:
-
- Shipped: 37.5% → 91.6%. Covers the full tool-call loop, session persistence on success/mid-turn error, hooks/profile/role/skill-manager wiring, and the remaining functional options.
Agent.GetSession's doc comment (previously claimed it returns nil for a missing session; it actually returnssessions.ErrSessionNotFound) has been corrected.
- Shipped: 37.5% → 91.6%. Covers the full tool-call loop, session persistence on success/mid-turn error, hooks/profile/role/skill-manager wiring, and the remaining functional options.
- [x]
RMI-OMNIAGENT-022OpenAI API server test coverage (target: 50%+) -
- Acceptance:
api/openaipackage coverage increases from 15.6% to 50%+; covers streaming, models endpoint, tool listing
- Acceptance:
-
- Shipped: 18.2% → 66.9%. Covers SSE streaming end-to-end, models list/retrieve with API-key auth, ogen<->internal type conversions, usage/tool-usage stores. Security fix, found in the process:
POST /openai/v1/chat/completionsbypassedsecurityHandler/API-key auth entirely —StreamingHandler.ServeHTTP(streaming.go) never called into the ogen-wrapped, auth-checked handler for POST requests, unlike/models. Fixed by applying the samesecurityHandler.HandleBearerAuthcheck directly inStreamingHandler.ServeHTTPbefore dispatch, with regression tests locking in both the rejection and the open-when-unconfigured cases.
- Shipped: 18.2% → 66.9%. Covers SSE streaming end-to-end, models list/retrieve with API-key auth, ogen<->internal type conversions, usage/tool-usage stores. Security fix, found in the process:
- [x]
RMI-OMNIAGENT-023OpenAI adapter test coverage (target: 50%+) -
- Acceptance:
openaiadapter package coverage increases from 19.9% to 50%+; covers multi-agent routing, chat completion, cron handler
- Acceptance:
-
- Shipped: 19.9% → 91.4%. Covers routing precedence, the
useSessiongate, streaming reassembly, and the cron handler end-to-end against a real in-memory scheduler; a shared httptest-backed fake LLM drives a real*agent.Agentwith no network access.
- Shipped: 19.9% → 91.4%. Covers routing precedence, the
- [x]
RMI-OMNIAGENT-024Voice package test coverage (target: 50%+) -
- Acceptance:
voicepackage coverage increases from 22.6% to 50%+; covers gateway, processor, providers
- Acceptance:
-
- Shipped: 22.6% → 96.2%. Covers the Gateway's call/session lifecycle and
ProcessWithAgent,NewGateway's provider/credential resolution (Twilio/Telnyx, error paths), and tool/handler conversion — fakes for the voice gateway/session/LLM provider drive real request marshaling with zero network I/O.
- Shipped: 22.6% → 96.2%. Covers the Gateway's call/session lifecycle and
- [x]
RMI-OMNIAGENT-025Skills package test coverage (target: 50%+) -
- Acceptance:
skillspackage coverage increases from 37.8% to 50%+; covers skill loading, execution, validation
- Acceptance:
-
- Shipped: 41.2% → 96.7%. Covers discovery/loading (directory + embedded-pack sources, dedup precedence, malformed manifests), the
Manager(Load/Get/All/Count/Available, Includes/Excludes ordering), andCheckRequirementsinstall-hint formatting.
- Shipped: 41.2% → 96.7%. Covers discovery/loading (directory + embedded-pack sources, dedup precedence, malformed manifests), the
Phase 6 — Context and Token Management¶
Theme: Implement the deferred context window and token counting features. Status: Complete — 5 of 5 items completed
- [x]
RMI-OMNIAGENT-026Model-specific token counting -
- Acceptance:
ModelTokenCounteruses tiktoken for OpenAI models, provider-specific counting for Anthropic/others; accurate to within 5% of actual usage
- Acceptance:
- [x]
RMI-OMNIAGENT-027LLM-based conversation summarization -
- Acceptance:
WindowStrategySummarizecalls LLM to summarize older messages; configurable summarization prompt; summary replaces N oldest messages
- Acceptance:
-
- Shipped:
Window.applySummarize(previously a stub) now calls an injectedSummarizeFunc, keeping the system message + most recent messages verbatim and replacing older ones with a single summary message; falls back to plain recency windowing and returns a*CompactionErrorif summarization fails or isn't configured.Engine.Applygained actx/error-returning signature and delegates toWindowinternally whenCompactionEnabled+CompactionThresholdare set (Engine.EnableCompaction), composing with its existing message/token windowing.agent.WithCompaction(threshold)wires this to the agent's own LLM client (agent/compaction.go'ssummarizeMessages, configurable viaConfig.CompactionPrompt) — a pure library capability, matching RMI-026's precedent of nogateway run/CLI wiring.
- Shipped:
- [x]
RMI-OMNIAGENT-028Autoreply template rendering -
- Acceptance:
autoreplypackage template TODO implemented; supports variable substitution in auto-reply messages
- Acceptance:
- [x]
RMI-OMNIAGENT-029WebSocket origin allowlist -
- Acceptance:
CheckOriginingateway/gateway.goenforces configurable allowlist; rejects requests from unlisted origins
- Acceptance:
- [x]
RMI-OMNIAGENT-030Gateway WebSocket authentication -
- Acceptance:
handleAuthingateway/handlers.govalidates tokens/credentials; supports API key and JWT authentication
- Acceptance: