Browse documentation

REPODESK DOCUMENTATION

Original Markdown from stonega/repodesk. This versioned snapshot includes proposals and research, not just shipped features. See the implementation evidence for current scope and limits.

View source at 521ccc0

Admin web panel

Status: P0 design contract with a local React Router implementation. See implementation evidence for the tested subset and deliberate UI choices. Embedding it as a Telegram Mini App remains optional.

Deployment and application shape

Use React Router 7 in SPA mode with Tailwind/shadcn components as needed. Put the frontend in web/ and build static assets into the existing Node Docker image. Hono serves /admin/* and /api/admin/* on the same origin. Serve the SPA fallback only for admin page requests, never for missing API endpoints. Frontend routes use client loaders/actions to call the API; authentication and authorization run on the server for every request. React Router SPA mode

No browser model SDK or provider key is needed: AI runs through Pi on the backend. The browser reads paginated data and polls status initially; add SSE only when useful. Public static assets can load before login, but contain no workspace data or secrets.

Pages and scope

PageP0 controls and informationAcceptance criteria
First-run setupClaim deployment, create local admin, configure workspace and bot, set up a GitHub App, enter the panelResumable; one initial admin; no public reinitialization. Successful model setup activates the bot automatically once Telegram reception and an enabled published skill are ready.
Sign-in/workspace selectorLocal admin sign-in; optional linked Telegram sign-in, authorized workspaces, operator-only New workspace entry in the selector, logoutLogin does not grant a workspace role; revoked sessions stop working. New workspace opens a fresh setup wizard and is selected when entering the panel.
OverviewLinked count cards for members, conversation threads, scheduled workflows and operator-visible coding tasks (opening the Codex task list); deployment-administrator cards for the configured Telegram bot and workspace GitHub App, with token editing in a Manage bot dialog and GitHub controls in a management dialog; team card showing saved configuration with one edit dialog and versioned form; broader bot/worker, group and budget status remain plannedLoading, empty, stale and failure states are visible; tenant-scoped metrics matching their detail lists.
Workspace settingsWorkspace activity status and Pause/Resume action; Settings follows Plugins in the sidebarConfirmation dialog explains the consequences; Cancel makes no change; versioned saves preserve other configuration and show conflicts. Pause is absent from the Overview team editor.
Bot settingsDisplay label, timezone, base instructions, response style, directed-response mode, pause switchValidated form, versioned save, audit entry, saved/effective version shown.
Model settingsOperator-configured providers and bot chat model, thinking level, optional capacity and token prices; saved summaries and modal editorsSuccessful model setup activates automatically when prerequisites are ready, without a separate activation card. Invalid settings rejected locally; provider capabilities require evaluation. Runs pin endpoint/thinking/prices at first execution; endpoint changes stop old runs.
Groups and accessConnected group/topic, owner, bot visibility, history coverage, opt-in collection, unlinkLinking verifies authority; no arbitrary chat ID can be used to obtain access.
WorkflowsCreate/edit draft, preview schedule and destination, approve, pause/resume, run now, delete; unlinked deployment administrators can inspect read-only schedule metadataSame policy and version checks as Telegram buttons; edits cannot bypass approval or reveal private task/destination content to unlinked administrators.
PluginsCompact Installed and Market catalog; dedicated detail pages for Code Truth, Codex and registered file extensions; operator-managed version/path/tool editing, enable/disable/remove, file status and revision conflictsDatabase-backed settings reach workers without restart; settings and revisions isolated per workspace; external market packages are discovery links and no code executes on API reads/saves.
GitHubManage GitHub modal for guided App creation, workspace OAuth, installation/repository selection and connected repository links, opened on Overview without navigation; GitHub callbacks return to Plugins; disconnect APIManifest state bound to operator/session/workspace; encrypted operator App credentials; one-use PKCE OAuth; verify user installation/repository access; installation tokens limited to selected repositories and Contents read.
Agent skillsCreate/import/edit, test, publish, enable/disable, scope, settings and version rollbackPermission-bounded skills; pinned workflow versions; disabling blocks dependent execution.
Shared instructionsList, edit, scope, provenance, versions, forgetNever lists other users' personal memories by virtue of admin role.
ThreadsCompact conversation summaries with Telegram user/group identity, latest activity and request counts; dedicated chronological conversations with aggregate statistics and links to individual run diagnosticsPaginate threads after grouping by saved identity; preserve workspace, list and request offsets. Names/usernames are display metadata; IDs and existing workspace authorization govern access. Unlinked deployment administrators can inspect retained messages. Existing cancel/retry/recovery controls remain on individual runs.
Usage and limitsRecorded/estimated usage, daily/monthly caps, reservations and blocked jobsChanges apply atomically; concurrent workers cannot overspend the displayed cap.
Members & accessSearch Telegram names/usernames/IDs and GitHub logins; manage active membership, roles and requests; fetch GitHub account choices in member forms; GitHub column contains only View, opening account/profile, status and repository access detailsAll active members can use the bot; roles determine available actions. GitHub associations require explicit selection and separate member verification. Preserve last-admin protection, tenant boundaries and revocation checks.
Privacy and auditRetention settings, deletion request/status, configuration/action auditDestructive changes show scope; logs omit credentials and raw private chat text.
Runtime logsOperator-only API/worker/polling/run/delivery events; severity/service/search filters, cursor pagination, auto-refreshStatic messages and allowed error codes; no secrets/private text; workspace metadata scoped to its operator; seven-day/10,000-entry retention.
Operator settingsReadiness of global bot/provider credentials, webhook state, allowed models, maintenance controlsDeployment-operator-only; workspace admins cannot modify global bot identity or webhook.

See first-run setup and agent skills for detailed P0 flows. Later: connector authorization/sharing, artifact library, scripted skill execution and billing. Do not display inactive placeholders as working features. The configuration panel must work without manually editing database rows.

Identity and authorization

Apply active workspace membership to bot access and retain role checks for panel administration. Regular membership grants no admin role.

On an uninitialized deployment, use the first-run wizard to create a local deployment admin, protected by a one-time host-issued claim token. Local admin login permits configuration before any Telegram token exists. Store password hashes and revocable server-side sessions; no public first-visitor signup.

After bot configuration, allow verified Telegram identity linking and optional Telegram web login for workspace users. Validate signed data and freshness server-side; use Secure/HttpOnly/SameSite cookies and reject replay/login-CSRF attempts. Workspace membership and roles remain separate from authentication. Telegram web login

The local deployment admin may configure credentials, initial workspaces and recovery. Workspace run history is visible in full to its deployment administrator and eligible workspace owners/admins, regardless of the run author or conversation. The deployment administrator does not need a linked Telegram identity to read these messages. Bot execution and run mutations still require a linked, eligible Telegram identity. Workspace admins cannot modify another workspace or deployment-wide secrets.

Require CSRF tokens/origin checks for mutations, rate-limit authentication and expensive actions, rotate sessions after login and privilege changes, and support logout/revocation. Escape output content; do not render generated HTML as trusted UI.

Configuration behavior

Repository summaries use the same shared card frame in Members & access, Manage GitHub, Codex, Review Bot and Code Truth: a muted surface, subtle border, rounded corners, wrapping names, compact badges and a common action area. Compact lists and cards with saved policy details share that styling. External repository links have accessible names and 44px targets; New/Edit remains separate from saved display. Member GitHub columns contain only View, opening account/status information and the complete saved repository list in a read-only modal.

Plugin detail pages show saved configuration as labels, values and statuses. Review Bot lists repository policies with New in the section heading and Edit on each saved record. New and Edit open a repository dialog; the normal display contains no repository form controls or page-wide Save settings action. Cancel discards the draft, failed saves keep the dialog open, and stale revisions require reloading saved settings before editing again. Repository removal is confirmed before saving. The GitHub webhook card also displays saved URL/secret status and opens its existing editor from Edit.

Admin and setup dropdown inputs share the sidebar workspace selector's trigger, menu and selected-item styling in both themes. Menus support keyboard navigation, type-ahead, Escape and outside dismissal; form validation and submitted values are preserved. Repository selectors retain their searchable input. Dropdown menus stay within the viewport and remain inside the owning dialog's focus boundary.

Successful saves and routine action confirmations appear in a shared floating toast, announced politely and dismissible manually or after six seconds. Hover and keyboard focus pause dismissal. Validation errors, readiness warnings and ongoing progress remain beside the relevant controls.

Store typed, validated settings with monotonically increasing versions. UI reads the current version and writes with an expected version; stale writes return a conflict with a diff/reload choice. Persist setting changes and audit entries atomically. Notify workers through version refresh, not in-memory mutations in the API process.

At run start, snapshot model, instruction and workflow versions. Routine edits apply to future runs. Emergency pause, membership revocation, budget restrictions and deletion are checked again before each costly/action step and before delivery. Workspace pause and resume are confirmed in a dedicated dialog on Settings. Pausing cancels queued/running assistant work and pending run deliveries; resuming allows new work and does not restart cancelled runs or deliveries. Model capacity is shown in deployment Model settings.

Operations keeps health metrics, deployment activity, workspace setup status and operator audit records in read-only summaries. New panel accounts, identity verification links, workspace access recovery and redacted run inspection open focused dialogs. Cancel discards input, failed requests preserve the draft, and pending requests lock dismissal and duplicate submission. Deployment pause/resume requires confirmation with the loaded deployment revision; conflicts require reloading before confirming again. Workspace-dependent actions remain disabled until active workspace choices load. Successful actions refresh the affected summaries and show a toast; account/link and diagnostic results remain readable on the page.

The first-run wizard accepts bot credentials; Model settings accepts provider credentials as write-only inputs in P0, encrypting them with a Docker-injected application key. Environment-provided keys may be referenced instead. Responses show status and safe labels only; credentials never enter model context, frontend storage or audit diffs. The database connection, and encryption key stay operator-level deployment settings.

API plan

Endpoint familyResponsibility
/api/setup/*Initial admin claim, authenticated setup draft, validation and activation
/api/admin/auth/*Local login, optional Telegram linking/login, session, logout
/api/admin/workspacesList authorized workspaces
/api/admin/workspaces/:id/settingsRead/update versioned bot/model/usage/retention settings
/api/admin/workspaces/:id/chatsList/link/unlink chat bindings and context collection
/api/admin/workspaces/:id/workflows/*Workflow drafts, previews, approval and lifecycle actions
/api/admin/workspaces/:id/skills/*Catalog, versions, tests, publication and assignments
/api/admin/workspaces/:id/instructions/*Scoped memory/instruction management
/api/admin/workspaces/:id/runs/*Authorized history, details, cancel and retry
/api/admin/workspaces/:id/threadsPaginated conversation summaries with saved Telegram user/group identity
/api/admin/workspaces/:id/threads/:threadChronological request/reply pages and whole-conversation statistics
/api/admin/workspaces/:id/members/*Membership and roles
/api/admin/workspaces/:id/usage and /auditPaginated accounting and audit metadata
/api/admin/workspaces/:id/deletionRequest/status of authorized purge
/api/admin/workspaces/:id/pluginsRead/update the workspace-scoped Pi extension registry with optimistic revisions and atomic audit
/api/admin/operator/*Deployment-wide health and restricted controls
/api/admin/updatesAuthenticated latest stable release, changelog and installation status
/api/admin/operator/updatesOperator-only approved update/retry queued to the host daemon; session/origin/CSRF and release fingerprint required

Group access cards display the last known Telegram group title with the ID below it, falling back to the ID when the title is unknown. Titles are captured on linking and subsequent group updates. Recheck bot visibility also refreshes the title for existing bindings; inaccessible groups retain their last known name.

These are proposed resource boundaries. Define shared request/response schemas before implementing forms; call domain services rather than duplicating Telegram logic.

UI acceptance and testing

Sign-in keeps its form and entered values visible while authenticating and loading the session and authorized workspaces. Its disabled submit button shows a spinner and Signing in… until home opens. Errors preserve the form and allow retry. First-account creation uses the same transition before opening setup. Opening or refreshing the app shows only the centered RepoDesk logo and brand text until deployment, session and workspace checks finish. Startup failures stay on that screen with Try again; only an unauthorized session opens sign-in. After sign-in, a protected API request returning HTTP 401 clears the session and workspace selection and opens sign-in at /admin immediately, including during background refresh or a save. Invalid credentials keep the sign-in form visible; HTTP 403 permission errors and other failures remain on the current page.

Structured responses use labeled details and lists with readable dates, statuses, booleans and currency rather than JSON dumps. Setup, workflow, skill, instruction, run, reconciliation and operator forms use explicit labeled controls, selection lists and tool checkboxes. Bound IDs and concurrency versions remain in request payloads without becoming editable fields. Failed saves preserve drafts and show field errors; pending saves block modal dismissal and duplicate submission.

The Threads list at /admin/threads?workspace=:workspaceId requests 25 compact conversation summaries. /admin/runs redirects there while preserving query parameters. Sidebar and Overview use Threads; Overview's counts.threads matches the list total. The existing counts.runs remains the individual request count for API compatibility.

GET /api/admin/workspaces/:id/threads?offset=0&limit=25 returns { mode, items, total, offset, limit }. Group all retained requests by valid saved thread identity before pagination; sort threads by latest request/completion time, with deterministic insertion order for ties. Private actors, bots, groups and native topics retain their persisted boundaries. Ignored/pending automatic-followup classifiers are not conversation turns. Requests without a valid retained thread record and scheduled requests remain separate entries with run-:runId keys; continuity is never inferred from user/chat IDs or timing.

Each summary has id, kind, a bounded title (first retained request, 120 characters), preview (latest answer or request, 200 characters), at, updatedAt, status, requestCount, user, optional group, topicId, up to three participants, and participantCount. User metadata contains only id, optional name and username; approved-request metadata is a fallback for older profiles. Groups use saved titles and IDs. No live Telegram profile/history lookup occurs. Lists omit execution transcripts, tool data, attempts and message/delivery bodies.

GET /api/admin/workspaces/:id/threads/:thread?offset=0&limit=25 returns { mode, thread, statistics, items, total, offset, limit }. Thread pages at /admin/threads/:thread?workspace=:workspaceId show a chronological page of request and answer pairs. Each item has run id, user, task, optional result, status, at, optional finishedAt and model. Statistics cover the whole retained conversation, independent of the current message page; the message count includes requests and recorded assistant replies. Run details retain execution transcripts and existing mutation/recovery controls. List and message pagination are independent: listOffset preserves the parent list; run links retain thread, threadOffset and listOffset for return navigation.

Both thread endpoints use the existing workspace-admin/deployment-operator read authorization, including access to private retained conversations. Cross-workspace thread IDs return 404 after workspace authorization; missing/malformed keys and invalid pagination are explicit errors. Offset defaults to 0 and must be a non-negative safe integer; limit defaults to 25 and must be an integer from 1 to 100. Loading, retry, empty and out-of-range pages retain headings/navigation and never show data from a previous thread/page.

The existing /api/admin/workspaces/:id/runs?offset=0&limit=25 API still returns individual request summaries with its original fields, pagination and authorization.

Run detail pages at /admin/runs/:runId?workspace=:workspaceId load the selected record from GET /api/admin/workspaces/:id/runs/:run. Missing or expired runs show an explicit error and a Back to Threads link; failed loads offer Try again. Known parent threads use Back to thread, preserving message and list pagination. A summary above the messages shows the displayed message count, distinct tool calls (including pending/blocked calls), model attempts, reported total tokens, cache hit rate and recorded actual USD spend. Tokens include uncached input, cache reads/writes and output across all attempts, including follow-up and compaction. Cache hit rate is cache-read tokens divided by all input tokens. Missing usage/charges stay unavailable and partial totals identify how many attempts have reported. An empty run has zero attempts/tokens/spend and no cache rate. The primary history list groups these requests into conversation threads. Run detail pages show model attempts as a numbered horizontal timeline, with time, status and reserved/actual USD amounts. Additional attempt metadata expands inside each card; overflow scrolls within the timeline on narrow screens.

Usage & budget displays a table of attempt times, models/run IDs, reservation statuses and reserved/actual USD amounts. The spend and monthly-limit summary stays above the table. Previous/next controls use the accounting API's 100-record pages, with URL offsets and visible record/page counts. Loading, empty and error states are explicit; the table scrolls horizontally within the card on small screens. Data loading preserves known headings, descriptions, controls and table columns. Overview immediately shows its count cards, connection cards when the session permits them, and team configuration labels, with skeletons for unknown counts, connection details and saved settings. Select the layout by route; pending Overview data must never show the audit table. Keep saved values visible during refreshes. Unknown values and records use skeletons; dependent actions stay disabled until the data arrives. Codex keeps its Configuration and Coding tasks cards visible, and initial errors end the skeleton state with an actionable retry. Skeletons respect reduced motion and expose named regions with busy states.

Common admin actions use Reicon outline icons through web/icon-button.tsx. Icon buttons are borderless and retain descriptive accessible names, hover titles, keyboard focus, 44px hit targets and disabled/busy states. Primary form submissions, authorization, approvals and actions needing consequence text retain visible labels. Existing confirmation and permission checks still apply. See UI rules. Routine pages, sections and the sidebar omit refresh buttons. Explicit text recovery actions appear after load failures or conflicting edits. Logs offer manual refresh when automatic updates are off or have failed; active coding tasks offer Check progress. The Overview team card shows the saved settings version and a compact grid of configuration labels and values. One Edit button opens a single form with the explanations and all changeable values; the fixed missed-run grace remains read-only.

Runtime logs share the Runs previous/next pagination component inside the data card, below the table, with 12px rows and a regular 14px current range between blue chevrons. Cursor history allows returning to earlier pages; the summary omits the Page label and has no total count. Filters, search and Latest logs reset pagination, and automatic refresh pauses on older pages. Loading disables both page actions; failed loads retain a route back to the previous page. Pagination remains visible after empty or failed loads and outside the table's horizontal scrolling area on mobile. An Auto-refresh menu replaces the checkbox, with 10-second, 30-second, one-minute (default), five-minute and Off options, plus Refresh now below a divider. Manual refresh retains the current page and disables during requests; the timer pauses while a request is pending. Latest logs remains the shortcut to the first page. The Overview connection cards link the configured Telegram bot handle and connected GitHub account name to their respective profiles in new tabs when those identities are available. The Manage buttons continue to open their existing dialogs. Model settings uses the same compact grid for saved provider configuration, key status, thinking level, effective capacity and price overrides. One Edit icon opens the model configuration modal; basic fields and advanced settings retain their validation and write-only key behavior. Cancel discards changes, failed saves keep the draft, and successful saves close the modal and refresh the summary. Price overrides support USD, CNY, TWD, HKD, EUR, GBP, JPY and SGD. Non-USD prices require an operator-entered USD exchange rate (USD per one currency unit). Saved prices show their currency code and rate; switching currency retains entered prices and clears the prior rate. Catalog prices and budget/usage accounting stay in USD. The sidebar workspace selector uses a panel-styled menu with a selected state and the operator-only New workspace action, which opens the setup wizard with a blank workspace form. Review Bot, Codex, Code Truth, plugin and site settings request failures use a floating error toast with the existing reload/retry control. These toasts use alert semantics and remain until dismissed or recovered, without shifting the page. Shared toasts use a neutral surface and subtle border/shadow, with a red error icon or green confirmation icon. Retry stays inline beside the message with a short visible label and descriptive accessible name; retry and dismissal retain 44px touch targets. Long messages wrap within the viewport in both themes, and toasts stay clear of the version/update control in the desktop footer or mobile admin header. Browser connection failures read “Couldn’t connect to RepoDesk.” Form validation and errors in open dialogs remain beside their controls. The compact account footer groups the username and sign-out icon, with a light/dark theme button at the right. Themes apply across the panel, sign-in and setup pages. The browser remembers explicit choices; otherwise the initial theme follows the system preference. The saved theme is applied before rendering the page.

Add/Create controls open the shared native modal in web/modal.tsx. Related record editors reuse it. The background is inert, keyboard focus stays inside, Escape/Cancel discard the local draft and focus returns to the opener. Failed saves preserve entered values and show errors inside the dialog; saves in progress disable dismissal and repeated submission. Dialogs scroll within a mobile viewport. Primary and Cancel buttons share one action row, with Cancel immediately after the primary action in visual and keyboard order. Narrow layouts wrap in that order. Repository and network dialogs apply to a local Code Truth draft; Save Code Truth still persists the configuration. Creating workflows/instructions still produces an approval proposal, and creating a GitHub App still requires GitHub confirmation.

Test unauthorized/expired sessions, role downgrades, forged workspace IDs, cross-tenant reads, stale saves, credential redaction and CSRF. Test admin scheduling and Telegram scheduling against the same backend contract.

Browser tests cover sign-in with a test identity adapter, changing bot instructions, saving a model configuration, conflicting edits, pausing a workflow and viewing the matching audit event. Inspect desktop/mobile layouts, keyboard navigation, form labels, confirmation dialogs and errors. Test identities must be disabled in production.

Release demonstration: configure the bot from the panel, see the new version take effect in Telegram, create/approve a schedule, inspect its run, then pause it from the panel and confirm no next run is dispatched.

The Plugins page also offers predefined Code Truth: enable/disable, add/remove GitHub repositories with optional descriptions and automatically generated IDs, index their default GitHub branches for the selected workspace, and sync/check index readiness with commit provenance. /api/admin/workspaces/:id/plugins/code-truth supports GET/PUT; /status supports POST with {}; the URL identifies the workspace. These share workspace plugin revision checks and operator authorization.

GitHub App setup and API documents the implemented workspace connection flow.

Workflow details (implemented)

Scheduled workflow cards show name/status, a readable daily or weekly schedule, the explicit schedule timezone, the next recurrence time and budget per run. The name links to /admin/workflows/:workflowId?workspace=:id&offset=:offset; direct visits, refreshes and Back to Workflows retain workspace and list position. The detail view adds upcoming recurrence times, owner/version/ID and, for linked authorized members, task, output format, destination/topic, context window and pinned skill version. Existing proposal and lifecycle controls remain available. Deleting from details returns to the list. Loading and failed reads have explicit states and retry; draft/paused/suspended times are labeled schedule previews.

GET /api/admin/workspaces/:id/workflows/:workflowId returns { mode, workflow, repositorySources? }. Member details include the full workflow and current accessible repository choices. Unlinked deployment operators receive only the same allowlisted schedule metadata as their list, never the task, chat, skill or historical specs. Both reads share visibility rules: deleted workflows are hidden; linked members see their own workflows and active workspace-group workflows. Missing or inaccessible workflow IDs return 404; foreign workspace access is denied. The list API remains compatible. Recurrence previews do not guarantee dispatch, which still depends on workspace and workflow policy. See workflow API examples.

Access request review (implemented)

The Members & access page includes Access requests and a shareable Telegram invite link that refreshes every 10 seconds with a countdown. Each token immediately adds one Telegram account as a regular member; copied links expire after 24 hours. Requests sent without an invite still need review. Pending rows show the Telegram ID, available display name and username, and request time. Approve access grants active regular membership and bot access; Reject request dismisses the request without granting access. Actions are disabled while saving, conflicts keep the request visible for reload, and successful approval refreshes the member list. See access control for tenant routing, retention, authorization and API behavior.

Custom admin domain (implemented)

Deployment operators can open Deployment → Site domain to add, edit or remove an HTTPS hostname for the admin panel. The setting applies to all workspaces; workspace administrators cannot read or change it. Edits use a dialog with preserved error drafts, an independent optimistic revision and atomic operator audit. The hostname accepts IDNs, normalizes to ASCII, and rejects URLs, paths, ports, IP addresses, wildcards and local hostnames. No additional dependency is required.

GET/PUT /api/admin/operator/site returns the effective address and callback URLs; PUT takes { revision, domain }, with domain: null restoring PUBLIC_ORIGIN. The saved domain is read from deployment state by both the app and worker. It updates allowed mutation origins, secure sign-in cookies, GitHub callback URLs and explicit Telegram webhook registration without a process restart. The configured PUBLIC_ORIGIN remains an allowed recovery address. Removed custom origins are rejected. Each hostname has its own host-only login cookie.

Saving does not provision DNS, configure the host proxy, issue certificates or perform external writes. The page explains DNS and HTTPS routing, shows a Caddy example, and labels availability as unverified. Changing the domain cancels pending GitHub flows and marks the webhook as requiring registration. Existing GitHub Apps need updated Homepage, Callback and Setup URLs in GitHub. Webhook registration is a separate explicit action after HTTPS is ready; polling requires no registration. See VPS deployment.

Consistent plugin details (implemented)

Installed plugin pages use a shared title row with an Enable switch at the right, compact configuration summaries, and separate repository and operational cards where applicable. The switch saves independently with the current revision and shows failures without changing the saved state. Code Truth repository edits remain a local draft until Save Code Truth; toggling enablement preserves that draft and saves only the previously saved repositories. Codex configuration uses one primary Save configuration action; sign-in, disconnect and connection recheck actions use secondary buttons.