Skip to content

Enrichment Features

End-user-facing capabilities layered on top of the agent runtime. Each ships as a tool/service + REST route + web page.

Fetch a URL, extract the readable content, and run reader actions on it.

  • Code: src/core/reader/ (fetch.ts, extract.ts, actions.ts)
  • Route: src/api/routes/reader.ts
  • Web: web/app/reader/page.tsx

The fetcher is SSRF-guarded. Extraction strips boilerplate to readable text.

Bounded, multi-source investigation that produces a cited report.

  • Code: src/core/research/ (jobs.ts, gather.ts, synthesis.ts, render.ts, persist.ts, service.ts)
  • Route: src/api/routes/research.ts
  • Web: web/app/research/page.tsx

Flow: plan queries → gather sources (SSRF-guarded fetch) → synthesize a sectioned, cited report → render. Depth (quick / standard / deep) bounds fan-out width and source count (DEPTH_BUDGET).

The web page keeps the investigation ID in /research?job=<id>. Opening that address again checks the existing job rather than starting another one. The Work navigation remembers this address while you move between pages in the current app session; bookmark it to return after closing the app. Missing or inaccessible jobs stop polling and offer an explicit status retry. Investigations are personal to the signed-in user, including when a shared workspace is selected. For research visible to teammates as it happens, ask your companion in a shared room.

On completion, Octipus attempts to save the Markdown report as a Documents record (category Research) and index it into the knowledge base. Indexing is fail-soft: if embeddings are unavailable, the document can still be saved and the reason is logged. Document persistence can also fail; the completed job can carry the report without a document link. Check documentId before treating it as a saved document.

Job tracking is stored in background_jobs. The job record survives a restart; the running computation does not resume automatically. The boot recovery sweep marks abandoned work as interrupted, exposed by the research polling API as error with a reason. Saved documents and any successfully created follow-up to-do remain durable. See src/core/research/jobs.ts and src/core/jobs/recover.ts.

The user’s personal to-do list. Agents can add, update, and complete items.

  • Tool: src/tools/tasks/ (TasksTool, displayed as To-Do List; tool id stays tasks, route /tasks)
  • Route: src/api/routes/tasks.ts, recurring items via routes/recurring-tasks.ts
    • the scheduler
  • Web: web/app/tasks/page.tsx (sidebar entry to-do)

Distinct from src/tools/task-state/ — a read-only inter-agent/workflow state tool that shares neither storage nor concept.

What next. GET /api/tasks?view=next (and list_tasks with view: "next") returns open tasks in next-action order — overdue → due today → high priority → new from email / research / reading in the last 48h → due this week → backlog — each with a bucket and a one-line reason. “Today” is the user’s calendar day: the page passes the browser’s zone as ?tz=, the tool uses the user’s saved timezone preference, and both fall back to UTC — never the server’s zone. The ranking is one pure function (src/core/tasks/rank.ts) shared by the tool, the API and the tasks page’s what next grouping (the default); the Daily Briefing asks the tool for this view rather than re-sorting.

Provenance. Every task carries source (user | agent | reader | research | email) and a sourceRef linking back to where it came from. The producers live in src/core/tasks/sourced.ts:

SourceHow a task gets created
readersave as to-dos on a Reader Action items result (POST /api/reader/tasks) — one task per bullet, linked to the article URL, category Reading.
emailTo-do on an open message (POST /api/email/message/:id/task) — subject as title, sender + snippet in notes, triage priority mapped onto task priority, category Email. The email-processor tool also tells the agent to create_task for mail that needs the user.
researchAutomatic on every finished Deep Research run — one Review research: … task pointing at the saved document (sourceRef.documentId), category Research.

One list of what happened to the user’s work since they last looked: agents that finished or failed, pipelines that completed or now wait on them, approvals blocking a run, to-dos other things created for them, and the unread notifications that arrived in the window (older unread mail is the inbox’s business, so “nothing happened” stays reachable). A pipeline that is still running is not news yet and is left out. Approvals and failures come first — they are the only items where nothing moves until the user acts.

  • Core: src/core/digest/away.ts — collectAwayDigest folds agents, pipelines, tasks, notifications and the in-process approval list; renderAwayDigest is the deterministic markdown of the same facts.
  • Route: GET /api/digest/away?since=<iso> (default: 24h; clamped to 30d).
  • Web: the first card on the dashboard (web/components/dashboard/away-digest.tsx). caught up remembers the moment in the browser and starts the next “away” there.
  • Briefing: a spawn_agent hook with actionConfig.awayDigestHours gets the rendered digest prepended to its prompt — the seeded Daily Briefing uses 24 — so the agent reads facts instead of spending a turn collecting them.

Every notification the platform raises for a user — an agent finished or failed, a pipeline completed, stopped or errored, an approval is waiting — lands in the notifications table and in the header bell. The inbox page is the full view of the same rows: filter by unread / agents / pipelines / approvals, mark one or all read, and follow each row to the thing that happened (the agent view, the pipelines page, the chat that is waiting for the approval).

  • Routes: src/api/routes/notifications.ts (GET /api/notifications with ?unread=1, ?type=<prefix>, limit, offset — filters apply in SQL so paging is over the filtered set; POST /api/notifications/:id/read, POST /api/notifications/read-all)
  • Web: web/app/notifications/page.tsx (sidebar entry inbox)
  • Producers: worker-spawner.ts, pipeline-manager.ts, approval-manager.ts via getNotificationService().notify(...); the metadata they attach (workerId, pipelineId, requestId) is what the inbox links on.

Batch, per-email AI classification and actions over Gmail / Microsoft 365.

  • Tool: src/tools/email-processor/ (EmailProcessorTool)
  • Core: src/core/email/ (send/normalize)
  • Route: src/api/routes/email.ts (send is gated)
  • Web: web/app/email/page.tsx

Recommends local Ollama models that fit the host’s hardware.

  • Code: src/capabilities/hwfit/ (catalog.json/catalog.ts curated catalog, scorer.ts, sizing.ts LIVE registry manifest sizing, install.ts)
  • Driver: src/capabilities/service.ts
  • Route: src/api/routes/capabilities.ts
  • Web: web/app/setup/page.tsx

Combines a curated model catalog with live registry manifest sizing and a hardware budget score to surface installable models the machine can actually run.


Edit this page in the repository.