Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/admin-dashboard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@caplets/core": minor
---

Add the self-hosted Caplets Admin Dashboard with Operator Client sessions, role-gated admin routes, dashboard access/catalog/Vault/runtime APIs, redacted operator activity logging, and a static dashboard UI shell.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ benchmark-results/
# Pi
.pi-lens/
!.pi-lens/semgrep.json
.pi-subagents/

# Playwright
.playwright-mcp/
Expand Down
36 changes: 36 additions & 0 deletions CONCEPTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,18 @@ A per-user native service managed by `caplets daemon` that runs local HTTP `capl

The Caplets Daemon is installed and updated through an install-time service contract. Runtime lifecycle commands operate on the installed service rather than changing its persisted serve or environment configuration.

### Current Host

The Caplets host that served the active dashboard session and owns the runtime state being administered in that session.

Current Host is a session-scoped administration target, not a product-wide singleton. The admin dashboard may initially operate only on the Current Host while preserving host-scoped terms for future multi-host enumeration and switching.

### Caplets Admin Dashboard

A browser UI served by the Caplets host for managing the Current Host's Caplets, remote clients, Vault, Project Binding state, daemon health, logs, and catalog-backed installs.

The Caplets Admin Dashboard is an operator surface over structured Caplets administration. It is not a raw config editor, a separate service, or a generic multi-host control plane in its first release.

### Daemon-First Setup

The local onboarding path where `caplets setup` prepares the user config and a healthy Caplets Daemon before configuring agent integrations.
Expand Down Expand Up @@ -225,3 +237,27 @@ Pairing Codes prove that a server-local operator approved a specific pending log
The stored local record for a trusted Caplets host, including the normalized host URL, host kind, selected workspace when applicable, and redacted credential status.

Remote Profiles are the source of truth for request credentials. Long-lived clients resolve current profile state when sending remote traffic instead of copying credentials into agent config or one-time startup state.

### Remote Client Role

The server-side authorization role assigned to a paired remote client after a Pending Remote Login is approved.

Remote Client Roles split ordinary runtime access from host administration. They are scoped to the Caplets host that issued the credentials so a future multi-host dashboard can preserve independent authority per host.

### Access Client

A paired remote client whose role allows Remote Attach, MCP, and Project Binding access without host administration.

Access Clients are for agent-facing and attach-facing runtime use. They do not authorize dashboard operations, remote-client administration, catalog install or update, Vault administration, or generic admin control.

### Operator Client

A paired remote client whose role allows dashboard and host administration operations against a Caplets host.

Operator Clients can approve or revoke remote clients, administer Caplets and catalog installs, manage Vault state, view diagnostics, and perform dedicated human-only reveal actions where allowed. Operator authority is granted through the same Pending Remote Login approval lane as ordinary access, but with an operator role request.

### Operator Activity Log

A host-owned record of sensitive Operator Client actions performed through the dashboard or operator admin surfaces.

Operator Activity Log answers what changed, when it changed, and which Operator Client performed the action. It is narrower than a compliance audit system and separate from daemon or protocol logs.
20 changes: 20 additions & 0 deletions CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,23 @@ _Avoid_: Inline blob, base64 result, download blob
**Caplets Vault**:
A runtime-owned encrypted string store whose values can be referenced from Caplets config with `$vault:NAME` or `${vault:NAME}`.
_Avoid_: Caplets Secrets, project secrets, shared encrypted project vault

**Remote Client Role**:
The server-side authorization role assigned to a paired remote client after a Pending Remote Login is approved.
_Avoid_: Device token type, browser permission flag

**Access Client**:
A paired remote client whose role allows Remote Attach, MCP, and Project Binding access without host administration.
_Avoid_: Regular device token, user token

**Operator Client**:
A paired remote client whose role allows dashboard and admin operations against the Caplets host, including remote-client administration, Caplet installation and configuration, and Vault administration.
_Avoid_: Admin device token, dashboard token

**Current Host**:
The Caplets host that served the active dashboard session and owns the runtime state being administered in that session.
_Avoid_: Only server, global host singleton

**Operator Activity Log**:
A host-owned record of sensitive Operator Client actions performed through the dashboard or operator admin surfaces.
_Avoid_: Daemon logs, compliance audit system
27 changes: 27 additions & 0 deletions apps/dashboard/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import react from "@astrojs/react";
import tailwindcss from "@tailwindcss/vite";
import { defineConfig } from "astro/config";

const dashboardApiTarget = process.env.CAPLETS_DASHBOARD_API_TARGET;

export default defineConfig({
output: "static",
integrations: [react()],
vite: {
plugins: [tailwindcss()],
...(dashboardApiTarget
? {
server: {
proxy: {
"/dashboard/api": {
target: dashboardApiTarget,
changeOrigin: false,
secure: false,
ws: true,
},
},
},
}
: {}),
},
});
25 changes: 25 additions & 0 deletions apps/dashboard/components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "base-nova",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/styles/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "lucide",
"rtl": false,
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"menuColor": "default",
"menuAccent": "subtle",
"registries": {}
}
35 changes: 35 additions & 0 deletions apps/dashboard/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "@caplets/dashboard",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"typecheck": "tsc --noEmit",
"build": "astro build",
"dev": "astro dev"
},
"dependencies": {
"@astrojs/check": "^0.9.9",
"@astrojs/react": "^6.0.1",
"@base-ui/react": "^1.6.0",
"@tailwindcss/vite": "^4.3.1",
"astro": "^7.0.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^1.23.0",
"next-themes": "^0.4.6",
"react": "^19.2.7",
"react-dom": "^19.2.7",
"shadcn": "^4.12.0",
"sonner": "^2.0.7",
"tailwind-merge": "^3.6.0",
"tailwindcss": "^4.3.1",
"tw-animate-css": "^1.4.0",
"typescript": "^6.0.3"
},
"devDependencies": {
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"vite": "^8.1.0"
}
}
Binary file added apps/dashboard/public/dashboard/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/dashboard/public/dashboard/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/dashboard/public/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/dashboard/public/icon-header-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/dashboard/public/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading