Operate
Optional integrations
Configure AI, MCP, OIDC, filesystem or S3-compatible storage without making them core dependencies.
v0.3.0 referenceReviewed
On this page
Core Hopya works with local accounts and filesystem storage—no AI, S3, SSO, telemetry, or vendor account required. Test optional integrations with your selected provider before production use.
AI Assistant
Operator secrets/settings belong only in the API environment.
| Setting | Contract |
|---|---|
AI_PROVIDER | Empty disables assistant |
AI_MODEL | Selected model |
AI_BASE_URL, AI_API_KEY | Optional provider configuration |
AI_MAX_OUTPUT_TOKENS | Integer 256–32,768; default 2,048; raising may increase cost |
| Provider | Default versioned base | Request / output budget |
|---|---|---|
openai | https://api.openai.com/v1 | /chat/completions, bearer; max_completion_tokens, includes reasoning; store:false |
anthropic | https://api.anthropic.com/v1 | /messages, x-api-key; max_tokens |
google | https://generativelanguage.googleapis.com/v1beta | /models/{model}:generateContent, x-goog-api-key; generationConfig.maxOutputTokens |
openai-compatible | Operator-supplied | /chat/completions; optional local bearer; max_tokens |
Base URLs include API version, not final method path. Local examples: http://model-server:8000/v1, http://ollama:11434/v1; verify the actual server. Groq/Mistral/DeepSeek may use their documented compatible base/model, but no endpoint/model version is guaranteed. Trusted private HTTP is allowed; remote credentials need HTTPS. Redirects are rejected; users/models cannot choose outbound URLs.
| Agent contract | Value |
|---|---|
| Endpoint | POST /api/v1/workspaces/:wid/agent |
| Request | Strict {message}, 1–8,000 characters |
| Permission | agent:use + items:read |
| Sent context | Message + ≤100 recent task titles/statuses/priorities/dates + ≤100 list names/IDs |
| Not sent | Member emails, descriptions, attachments, keys, other workspaces |
| Response | {reply,proposal?}; proposal title, optional description, nodeId, dueDate, priority |
| Conversation | Single-turn; displayed history stays in browser memory, not stored/automatically resent |
| Bounds | Four concurrent requests; 45 seconds for headers and body; bounded validated model JSON |
The agent never mutates tasks. Review/edit the proposal and choose Confirm and create through ordinary validated REST. It cannot delete tasks, run shell commands, browse arbitrary URLs, or change permissions. Task-content prompt injection and model advice remain untrusted.
AI lifecycle, privacy, and provider compatibility
- SQL selects bounded lightweight metadata, not whole-workspace data then slicing. List and current credentials/permissions are rechecked after provider wait before answer delivery/audit.
- Audit records action/outcome only, never prompt/answer. Busy:
429,Retry-After: 1; provider timeout/failure: sanitized502, no successful-answer audit. - Close/switch workspace aborts browser request. Detected client disconnect cancels provider HTTP/body and releases slot; normal POST-body completion is not disconnect. Controlled real-HTTP fixtures exercised these cases, not simulated clocks.
- Cancellation cannot retract sent context, guarantee remote cancellation/billing cessation, or immediately stop remote work after revocation. Verify proxy disconnect propagation and provider policies.
- Native OpenAI budgeting follows official SDK parameters, which deprecate
max_tokensfor reasoning models.store:falseis not a zero-retention guarantee. Review privacy, retention, billing, and response/time bounds.
MCP
Hopya uses the official TypeScript MCP SDK v1. Both transports call the same REST permission boundary.
| Transport / setting | Configuration |
|---|---|
| Stdio | HOPYA_API_URL (origin only), HOPYA_API_TOKEN; after npm ci and API build, run node apps/api/build/bin/mcp.js |
| SSE | Admin Site settings enables /api/v1/mcp/sse; disabled by default; personal bearer header only |
| Read tools | list_workspaces, get_workspace, list_items, get_item |
| Optional write tools | create_item, update_item, delete_item; API/stdio process HOPYA_MCP_ALLOW_WRITES=true |
| SSE sessions | Four per user / 32 per instance; 30 minutes; disable closes them; message POSTs reauthenticate |
Exposing tools does not approve writes. The MCP host must enforce human approval per mutation. Leave writes disabled if it cannot. Tool annotations are hints, not enforcement; REST RBAC/validation/version checks/revocation still apply.
| Reader / client rule | Contract |
|---|---|
list_items | One {items,nextCursor} page; limit 1–500, default 200; existing filters + cursor |
| Completion | Follow non-null cursors with same filters; first page is not all tasks |
| Buffer bound | At most 4 MiB incoming UTF-8; cancel when exceeded; large individual records/metadata may need REST even at limit 1 |
| Bound meaning | Response buffering, not total process memory or model context |
| Identity | Dedicated minimally authorized account; tokens inherit all account permissions, no separate scopes |
| Updates | Exact expectedUpdatedAt to avoid stale writes |
| Secrets / stdout | Private client environment/secure headers; no token in args/URLs/logs/source; no non-protocol stdout wrappers |
OIDC
See OIDC setup for a compatible provider. Operator owns provider deployment, recovery, MFA, and lifecycle policy.
| Configuration / route | Contract |
|---|---|
| Provider | Exact OIDC_ISSUER, client ID, provider-required secret; client_secret_post; HTTPS everywhere |
| Callback | ${APP_URL}/api/v1/auth/sso/callback |
| Flow routes | GET /api/v1/auth/sso, then callback |
| Validation | PKCE S256, random state/nonce, hashed browser-bound cookie/state, ten-minute one-use expiry; SDK signature/issuer/audience checks |
| Persistence | No tokens/claims persisted or logged; no request-selected redirect host |
| Provisioning default | OIDC_AUTO_PROVISION=false; local admin setup first |
| JIT enabled | Valid verified non-colliding email → non-admin account, no existing membership; local registration separately controlled |
| Existing identity | Exact issuer/subject, not email; suspension blocks it; local logout is not IdP-wide logout |
Matching email never links accounts automatically. Admin OIDC identities explicitly links independently verified issuer/subject. API: GET/POST /api/v1/admin/oidc-identities, DELETE /:id.
- Unlink revokes all target sessions/tokens and blocks matching in-flight exchanges; protects last passwordless method.
- A fresh verified-email JIT enrollment may still create a different non-admin account; unlink is not an upstream ban.
OIDC_ALLOW_INSECURE_HTTP=trueis loopback-test-only and rejected in production, not an HTTPS workaround.
Attachments
| Backend | Configuration / obligations |
|---|---|
| Filesystem | STORAGE_DRIVER=filesystem; opaque private objects under DATA_DIR/objects |
| S3 | AWS default credential chain; S3_BUCKET, S3_REGION, optional S3_ENDPOINT, S3_FORCE_PATH_STYLE; bucket must exist and be private |
| S3 access | Dedicated bucket, object get/put/delete only; no public ACL; trusted local HTTP allowed, remote TLS required |
| Compatibility | Conditional writes and other SDK behavior vary; verify the actual service |
Prefix: /api/v1/workspaces/:wid/items/:id/attachments.
| Method | Path | Contract |
|---|---|---|
| GET | Collection | {id,name,size,contentType,createdAt} metadata |
| POST | Collection | {name,contentType,data} canonical base64; task read/write; decoded ≤10 MiB; JSON ≤15 MiB, proxy ≤20 MiB |
| GET | /:attachmentId | Authorized private bytes; forced attachment and nosniff, not inline HTML |
| DELETE | /:attachmentId | Transactional metadata revocation; physical failure tracked with cleanupPending:true |
Authorization is rechecked after storage waits. Filenames never become paths/keys. Failed uploads are compensated; uncertain writes/deleted-task objects use a durable ledger. Hourly bounded cleanup handles unreferenced objects older than 24 hours, ≤100 per run. Admin status exposes backlog; failed objects retry later.
Changing driver/bucket/endpoint is not migration. Objects record a backend fingerprint with no silent fallback. Preserve old settings, transfer/verify bytes before metadata changes, and back up S3 versions separately. Workspace export has metadata, not bytes/keys; follow full backup.
Body And Comment Images
| Operation | Contract (paths after /api/v1) |
|---|---|
POST /workspaces/:wid/images | Base64 file fields + kind (task-body, task-comment, document-comment) + resource ID; only new task body may omit resource |
| Upload result | Private url, downloadUrl, expiresAt; uploader-only pending preview; 24-hour expiry |
| Content save | Validate/claim references transactionally; body images become attachments |
DELETE /workspaces/:wid/images/:imageId | Caller’s uncommitted draft only |
| Inline reads | Image /:imageId/inline or attachment /inline; current owning-resource read; comment tombstones revoke images |
| Raster limits | PNG/JPEG/GIF/WebP, ≤10 MiB / 40 megapixels; MIME from bytes; nosniff, sandbox, private/no-store |
| Rendering | Only private image paths; remote tracking, arbitrary URLs, data URLs, SVG inert |
| Export v8 | Committed image ownership/attachment metadata, no bytes/drafts/keys; ordinary downloads forced attachments |
See image and draft behavior for recovery and cleanup.
Verification Boundaries
| Integration | Application boundary | Operator verification |
|---|---|---|
| Filesystem | Private keys, access checks, bounded uploads, deletion ledger/cleanup | Disk monitoring, restore, sustained workload |
| S3 | Signed private requests, bounds, rechecks, tracked cleanup | Provider/policy/versions/lifecycle/remote restore |
| OIDC | PKCE/state/nonce, issuer-subject, local revocation | Access policy, MFA, recovery/logout/deprovisioning |
| AI | Bounded context/output, deadlines, rechecks, proposals only | Model behavior, retention/cost/region, cancellation |
| MCP | Authenticated REST, read defaults, optional mutations | Host security, human approval of every write |