# Advanced Hope chat surfaces Implementation contract, not a deployment receipt. All routes authenticate via existing current_user (bearer or cookie with mutation Origin checks). Owner is derived server-side. Missing/cross-account/deleted objects return404; revoked sessions401. Hermes alone runs tools/reasoning. Provider credentials, URLs, raw job configuration and disk paths are never public. ## Attachments - POST `/api/attachments`: raw bytes, MIME `Content-Type`, `X-Filename` display name. Returns201 `{attachment}`. No multipart wrapper. - GET `/api/attachments`: `{attachments:[],next_cursor:null}` (bounded first200). - GET `/api/attachments/{id}`: `{attachment}`. - GET `/api/attachments/{id}/content`: private bytes, download disposition, no-store, nosniff. - DELETE `/api/attachments/{id}`: `{ok:true}`. Removes stored bytes and tombstones metadata. Attachment exactly `{id,filename,mime,size,extraction_status,created_at}`. IDs UUID hex32, Unix timestamps. Extraction statuses ready|truncated|image|unavailable|encrypted|failed. Supported MIME text/plain,text/markdown,application/pdf,image/png,image/jpeg,image/webp. Defaults8MiB per upload,64MiB per account,512MiB global disk; MIME mismatch415, invalid filename422, limit413. No HTML/SVG, arbitrary paths or remote fetch. UTF8 text extracted, PDFs via pypdf (encrypted/failure explicitly blocked as provider input). Text capped100000 characters. Images are inline image_url payloads only for explicitly qualified selected model; otherwise409. Signature validation does not imply antivirus or full image decoder validation. Core integration `FeatureStore.provider_content(owner, attachment_ids, vision=False)` is async. At most8 distinct IDs. Never provider-input another owner's upload. Images use OpenAI message-content shape, not guessed Responses schema. Core supplies qualified vision flag. Local store persists in injected Accounts DB with FK plus private flat files. Account deletion denies access immediately and retains disk data by policy; no implicit erase. ## Artifacts - GET `/api/artifacts`: `{artifacts:[],next_cursor:null}` (bounded first200). List entries metadata only, omitting content; select GET detail to load content. - POST `/api/artifacts` JSON `{title,kind?:"markdown",content?:""}` →201 `{artifact}`. - GET `/api/artifacts/{id}?revision=N`: `{artifact}`, historical content optional. - GET `/api/artifacts/{id}/versions`: `{versions:[{revision,created_at}],next_cursor:null}`, descending revision. - PATCH `/api/artifacts/{id}` JSON `{revision,title?,kind?,content?}` → `{artifact}`; missing/stale revision409. - GET `/api/artifacts/{id}/export?revision=N`: UTF8 download, text/plain with .md for markdown, otherwise .txt. No executable inline HTML, PDF/DOCX generation claims. - DELETE `/api/artifacts/{id}` → `{ok:true}`; historical versions inaccessible after tombstone. Artifact `{id,title,kind,revision,content,created_at,updated_at}`. kind text|markdown|code. Title1–160 chars, default512KiB UTF8 content,200 artifacts including retained tombstones/account,100 versions/artifact. Cumulative retained version UTF8 bytes max32MiB/account and256MiB globally. Versions are not silently trimmed: explicit version limit/storage quota returns413, including deleted retained versions. Revision starts1, increments each edit. Historical versions currently retain content and time but title/kind reflect current metadata (not historical title). ## Scheduled tasks Qualified gateway exact mapping `/api/jobs`; no second scheduler. Provider operations authenticated with account's private Hermes key. Public delivery is forced local; client cannot select providers, scripts, base URLs, external recipients or tools. - GET `/api/tasks` → `{tasks:[],next_cursor:null}`; gateway query include_disabled=true. - POST `/api/tasks` `{name,schedule,prompt,repeat?,paused?}` →201 `{task}`. Schedule is a Hermes schedule string, not a fabricated UI cron dialect. name1–200 chars, schedule1–200 chars, prompt1–5000 chars, repeat positive integer, paused boolean. - PATCH `/api/tasks/{id}` `{name?,schedule?,prompt?,repeat?,enabled?}` → `{task}`. No optimistic revision supported by pinned Hermes jobs API. - DELETE `/api/tasks/{id}` → `{ok:true}`. - POST `/api/tasks/{id}/pause|resume|run` → `{task}`. Run triggers Hermes execution, not a Hope agent loop. Task projection whitelist `{id,name?,schedule?,prompt?,enabled?,repeat?,created_at?,last_run_at?,next_run_at?}`. IDs hex12. Only id is guaranteed; optional fields preserve exact gateway type, clients must tolerate absent timestamps. No task-output-history API has been qualified. Invalid remote scheduling errors sanitized; unsupported capability501, unavailable503, upstream failure502. ## Memory controls No gateway memory API exists. Trusted control adapter accesses only retained account `home/memories/MEMORY.md` and `USER.md`, never arbitrary file paths or separately authenticated WebUI. - GET `/api/memory` → `{sections:[{section:"memory",content,revision},{section:"user",content,revision}]}`. - PUT `/api/memory/{section}` `{content,revision}` → `{section,content,revision}`. Revision SHA256 hex content digest. Empty content explicitly clears that section. UTF8 max64KiB/section. Unknown section404, stale revision409, unavailable storage503, unqualified adapter501. Updates persist files; already-running Hermes sessions may retain cached memory until a later run/session reload. No claim of live memory-cache invalidation. Do not confuse clearing files with deleting conversation history or all data. Protected fixed directories and no-follow file opens; runtime has independent filesystem writes, so revision is best-effort against concurrent Hermes edits, not cross-process transaction locking. ## Honest statuses and sync - GET `/api/connectors` → `{connectors:[],available:false,reason,toolsets:[{name,enabled,configured}]}`. Read-only native tool configuration statuses from exact authenticated `/v1/toolsets`. No qualified connector credential/settings write API; do not present fabricated working OAuth/integration switches. Raw credentials/configuration are never returned. - GET `/api/research` → `{available:bool,mode:"hermes_tools"|null,reason:string|null}`. Enabled only when the actual account manifest advertises enabled/configured `web` with both `web_search` and `web_extract`. Capability lookup failure is unavailable, never optimistic true. Native research means one ordinary Hermes run with source-verification/citation instruction, not a second Hope reasoning loop or special upstream research endpoint. - Core message extension target POST `/api/conversations/{id}/messages` adds `mode?:"normal"|"research"`. Core must persist mode in idempotency payload and run settings; research calls `FeatureProvider.research_instruction(owner)` and supplies the returned static evidence/citations instruction to that same native Hermes run. Unqualified tools409. This module does not itself edit core message acceptance. - GET `/api/features/sync?after=0` → `{changes:[{sequence,kind:"attachment"|"artifact",id,deleted,created_at}],cursor}`; max200 per response, owner-filtered tombstones. This cursor is independent of core conversation sync. Core merges `local_capabilities(store)` and account-qualified `FeatureProvider.feature_capabilities(owner)` into its one `/api/capabilities`. Local helper reports image/tasks/memory false by default; provider qualifies jobs, managed auto vision, and available fixed memory storage. Constructor `FeatureStore(accounts, root_path, limits=None)`; router `create_feature_router(store, provider=None)`; default `FeatureProvider(accounts,http_client=None,state_dir=None)` has `aclose()` which app shutdown must call. Memory root defaults HOPE_HERMES_DATA_DIR matching provisioner. Research source verified pinned `749220ef` gateway handler `_handle_toolsets` and exact web toolset expansion. No live/deploy qualification performed here. ## Private conversation exports `create_export_router()` from `control.chat_exports` uses injected `app.state.chat_store`. - GET `/api/conversations/{id}/export?format=json|markdown` → authenticated attachment download. Defaults json. JSON `{version:1,conversation,messages:[]}` includes entire chronological message history, not a paginated first page. Only existing public projections, no private Hermes IDs, tool reasoning/events, account credentials or URLs. Markdown preserves original text/citations, exports as text/plain `.md` attachment rather than executable HTML. - Full export is bounded16MiB encoded output and10000 messages; oversized413, unsupported format422, cross-account/deleted404, revoked401. Session revalidated before final response. Attachment IDs preserved but private upload bytes not embedded. No public share links, remote upload or public artifacts. - Existing artifact export remains `/api/artifacts/{id}/export?revision=N`; exports selected exact stored content. Native model-generated artifacts require core capture/edit linkage, not an invented Hermes file API.