Add optional self-hosted mode with SQLite-backed UUID artifact storage#18
Add optional self-hosted mode with SQLite-backed UUID artifact storage#18
Conversation
…torage
Adds a separate self-hosted variant that stores agent-render payloads in
SQLite under UUID v4 keys and serves them at /{uuid} routes through the
existing viewer UI. This is an optional add-on for power users and agents
who need persistent short links or payloads exceeding the fragment budget.
- selfhosted/src/server.ts: Express server with CRUD API and viewer route
- selfhosted/src/db.ts: SQLite database with 24h sliding TTL
- selfhosted/Dockerfile + docker-compose.yml: container deployment
- src/lib/payload/injected.ts: viewer-shell integration for server-injected envelopes
- skills/selfhosted-agent-render/SKILL.md: agent workflow skill
- Updated docs across architecture, deployment, payload-format, testing, and dependency-notes
- 8 new unit tests for injected envelope resolution (all artifact kinds, validation, TTL)
The existing static fragment-based app is fully preserved and unmodified.
https://claude.ai/code/session_01FWECp4ZWSgoxbPvzhZbp5n
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (22)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Deploying agent-render with
|
| Latest commit: |
56956c9
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://9157da24.agent-render.pages.dev |
| Branch Preview URL: | https://claude-add-self-hosted-app-p.agent-render.pages.dev |
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Files Reviewed (22 files)
Review NotesThe implementation is well-structured with proper security considerations:
The self-hosted variant is properly isolated from the default fragment-based mode, maintaining backward compatibility as documented. Reviewed by minimax-m2.5-20260211 · 671,948 tokens |
There was a problem hiding this comment.
💡 Codex Review
agent-render/src/components/viewer-shell.tsx
Lines 369 to 370 in 66d7596
When the viewer is opened from /:uuid, this callback re-encodes the whole envelope into window.location.hash. That works only for fragment-sized bundles, but self-hosted artifacts are allowed up to 1 MB while decodeFragmentAsync() still rejects hashes over 8,000 characters in src/lib/payload/fragment.ts. For any multi-artifact payload that only fits in self-hosted mode, selecting another artifact replaces the working injected view with a too-large error state.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| COPY selfhosted/package.json selfhosted/package-lock.json* ./ | ||
| RUN npm ci --omit=dev |
There was a problem hiding this comment.
Add a selfhosted lockfile or stop using npm ci
This image copies only selfhosted/package.json and then runs npm ci --omit=dev, but rg --files selfhosted shows there is no selfhosted/package-lock.json in the repo. npm ci exits with EUSAGE without a lockfile, so the documented Dockerfile / Compose deployment path fails before the image is even built.
Useful? React with 👍 / 👎.
|
|
||
| # Install server dependencies | ||
| COPY selfhosted/package.json selfhosted/package-lock.json* ./ | ||
| RUN npm ci --omit=dev |
There was a problem hiding this comment.
Install the runtime loader used by
npm start
CMD ["npm", "start"] resolves to node --import tsx src/server.ts in selfhosted/package.json, but this image installs with npm ci --omit=dev, which drops tsx because it is only listed under devDependencies. Even after fixing the lockfile problem, the container will still exit at startup because the TypeScript loader it relies on is missing from the runtime image.
Useful? React with 👍 / 👎.
| try { | ||
| const parsed = JSON.parse(payloadStr); | ||
| if (!parsed || typeof parsed !== "object" || parsed.v !== 1 || !Array.isArray(parsed.artifacts)) { | ||
| res.status(400).json({ error: "Payload must be a valid agent-render envelope (v: 1, artifacts array required)." }); |
There was a problem hiding this comment.
Reject envelopes the injected viewer cannot open
The POST/PUT validation only checks for v === 1 and an artifacts array, so it still accepts envelopes that resolveInjectedEnvelope()/normalizeEnvelope() reject later—e.g. empty bundles, duplicate artifact IDs, or malformed diff artifacts. In those cases the API returns success and a UUID, but opening that UUID immediately lands on the viewer's invalid-envelope state instead of a renderable artifact.
Useful? React with 👍 / 👎.
Summary
This PR adds an optional self-hosted variant of agent-render that provides server-backed artifact storage as an alternative to the default fragment-based sharing. The self-hosted mode stores payloads in SQLite under UUID v4 keys and serves them via a simple Express API and viewer routes, enabling persistent short links and support for larger payloads without fragment-length constraints.
Key Changes
Self-hosted server implementation (
selfhosted/)POST /api/artifacts,GET /api/artifacts/:id,PUT /api/artifacts/:id,DELETE /api/artifacts/:id,POST /api/cleanup/:uuidthat injects stored payloads into the static HTML template viawindow.__AGENT_RENDER_ENVELOPE__Viewer integration
src/lib/payload/injected.tsmodule that resolves server-injected envelopes fromwindow.__AGENT_RENDER_ENVELOPE__src/components/viewer-shell.tsxto check for injected envelopes on mount before falling back to fragment decodingDocumentation and configuration
skills/selfhosted-agent-render/SKILL.mdwith deployment guides (systemd, pm2, Docker Compose), API examples, and auth patternsdocs/deployment.md,docs/architecture.md,docs/payload-format.md, anddocs/testing.mdwith self-hosted informationREADME.mdandAGENTS.mdto reference the optional self-hosted variant.env.examplefor self-hosted configurationTesting
tests/injected.test.ts) covering valid/invalid JSON, envelope validation, duplicate artifact IDs, and all artifact kindsNotable Implementation Details
datetime()function with a configurable modifier (default 24 hours) for sliding-window expiryhttps://claude.ai/code/session_01FWECp4ZWSgoxbPvzhZbp5n