Skip to content

v1.4.8

Choose a tag to compare

@github-actions github-actions released this 09 Oct 01:16
· 24 commits to main since this release

Release Notes v1.4.8

Released: 2026-10-09

This release adds a Team page: a per-organization view of who captured, created, and completed what, scoped strictly to what the viewer is already allowed to read. Supporting it required server-owned completion attribution on tasks (completed_at, completed_by) and a new activity rollup that excludes derived, projected, and migrated rows so one act counts exactly once.

🌟 Highlights

✨ Team activity page at /team

New route under apps/web/src/app/(main)/team/ showing a people grid and a newest-first activity feed grouped by day. Each teammate card carries role badge, per-kind counts (captures, tasks created, tasks completed, decisions, notes, procedures), relative last-active time, and an activity bar. Clicking a card narrows the feed to that person without changing the counts.

✨ GET /api/activity/team endpoint

New router in apps/api/src/sibyl/api/routes/activity.py returning TeamActivityResponse: resolved window, people with counts, and up to 100 recent events with a truncated flag. Query params are window (24h | 7d | 30d, default 7d), repeatable project_id, and optional actor_id. Requesting a project the caller cannot read returns 403 project_scope_denied; empty project strings return 422.

🔒 Visibility is the existing read policy, not a new grant

The rollup in activity_rollup.py resolves a ReaderScope once, pushes a private-scope clause into the SurrealQL window scans, then re-checks every row with entity_matches_list_filters() and raw_capture_visible_to_reader(). Private rows surface only to their own principal; API-key readers stay bound to their memory_grants. No count or feed item comes from a row the caller could not already list.

✨ Server-owned task completion attribution

New sibyl_core/tasks/completion.py centralizes transition rules. Any path to done (REST complete, PATCH /tasks/{id}, MCP update_task, manage) now stamps completed_at and completed_by from the authenticated caller. Re-completion is a no-op, reopening clears both fields, archiving preserves them. modified_by is likewise stamped server-side on every status edit.

♻️ One act counts once

Derived entity types (topic, passage, community, document), projection categories, reflection surfaces, and migration-carried rows are dropped before classification. mark_raw_memory_projected_entity() links an MCP capture to the graph row it became, mirroring the REST sidecar behavior, so a remember that also creates an entity is not counted twice.

🤖 Activity API

  • activity_rollup.py runs three reads concurrently: list_org_members(), the graph window scan, and list_raw_memories_created_between(). Row filtering and capture lifecycle checks run off the event loop.
  • Windows are half-open [since, until) intervals resolved in UTC; creation events use created_at, completion events use the server-owned completed_at.
  • The recent feed sorts by (at DESC, kind, id) for stable ordering and caps at RECENT_LIMIT = 100, setting truncated when more existed.
  • Each event carries a navigable href (/tasks/{id}, /epics/{id}, /projects?id=, /memory/captures?id=) with URL-safe encoding.
  • A task that reached done without a completed_at record stays uncounted rather than being credited to a guess.
  • Response includes both project_id (set only for a single-project request) and project_ids (every requested UUID, in request order).

🖥️ Web

  • Components under apps/web/src/components/team/: TeamActivityView, PersonCard, PersonAvatar, ActivityFeed, WindowSwitcher, ProjectScopeSelect.
  • window and project scope persist in the URL (?window=, ?projects=); the person filter is session-local and resets on navigation.
  • useTeamActivity() in lib/hooks/activity.ts dedupes and sorts project IDs for a stable query key, uses keepPreviousData so the prior answer stays visible during a scope switch, and drops the placeholder after a failure so a retry shows a clean load instead of stale data.
  • First visit with no URL scope defaults to the first active project rather than "all", avoiding an unbounded historical scan.
  • Error states distinguish project_scope_denied (offers "Show every project") from generic failures (offers Retry), and a partial refresh failure keeps the last good answer behind a warning banner.
  • /team added to lib/constants/navigation.ts in the overview section alongside Dashboard.

🔒 Permissions and policy

  • WORK_ITEM_ACTOR_METADATA_KEYS (completed_at, completed_by, modified_by) is stripped from client payloads in memory_policy.py, so a request cannot reassign work to another member or backdate a completion.
  • New work_item_actor_metadata() lifts those stored values out before a policy strip and reattaches them afterward, keeping server attribution intact through backup restore and archive import.

⚡ Persistence

  • list_raw_memories_created_between() scans idx_raw_captures_org_created over the window, selecting only the fields the rollup needs (no body, no vectors) and excluding sidecars and projected captures at the query level.
  • Graph window scans use idx_entity_updated and drop derived entity types inside the query to keep the scan small.

✅ Tests and fixtures

  • New: apps/api/tests/test_activity_rollup.py, apps/api/tests/test_routes_team_activity.py, packages/python/sibyl-core/tests/test_task_completion.py, apps/web/src/app/(main)/team/team-content.test.tsx, apps/web/src/lib/hooks/activity.test.tsx.
  • team-activity.fixtures.ts provides a shared dataset (six members across roles, fourteen events across three projects) reused by tests and the team-activity-view.stories.tsx Storybook scenarios: active, truncated, quiet, loading, and failed.

Breaking changes

  • mirrors_source_status requires sync=true. The new field on the task update request is intended for sibyl migrate to-team alone: it marks a status write that mirrors a source task so no completion is recorded. Passing it on a queued (async) update returns 422, because the completion decision has to happen under the entity lock that holds the read.
  • Completion fields are no longer client-controlled. completed_at, completed_by, and modified_by are stamped from the authenticated caller on every status write. Payloads setting these values are stripped.
  • Reopening a task clears its completion record. A done to open transition now resets completed_at and completed_by. Integrations that read a historical finisher off a reopened task will see null. Archiving a done task still preserves both fields.

Upgrade notes

  • Pure patch bump across the deployment surface: VERSION, charts/sibyl, charts/surrealdb, docker-compose.quickstart.yml, the Ansible role defaults, and both pyproject.toml pins move 1.4.7 to 1.4.8. No config shape changed.
  • Docker: sibyl docker upgrade --tag 1.4.8. Helm: set backend.image.tag and frontend.image.tag to 1.4.8. Ansible: sibyl_version defaults to 1.4.8.
  • Tasks completed before this release have no completed_at record and will not appear as completions in the Team feed or counts. Attribution builds from new completions forward.
  • If you script task status writes, drop any completed_at / completed_by / modified_by fields from payloads; they are ignored.
  • No migration is required. The idx_raw_captures_org_created and idx_entity_updated indexes carry the activity window scans.

Install

Local server

curl -fsSL https://raw.githubusercontent.com/hyperb1iss/sibyl/main/install.sh | sh -s -- --version 1.4.8

Remote CLI

curl -fsSL https://raw.githubusercontent.com/hyperb1iss/sibyl/main/install.sh | sh -s -- --remote --version 1.4.8
sibyl init --remote https://sibyl.example.com
sibyl auth login

Homebrew

brew install hyperb1iss/tap/sibyl
sibyl up

Arch Linux (AUR)

paru -S sibyl
sibyl up

Headless server

curl -fsSL https://raw.githubusercontent.com/hyperb1iss/sibyl/main/install.sh | sh -s -- --version 1.4.8 --no-open

Kubernetes (Helm)

helm repo add sibyl https://raw.githubusercontent.com/hyperb1iss/sibyl/gh-pages
helm repo update sibyl
helm upgrade --install sibyl sibyl/sibyl --version 1.4.8

Artifacts

This release includes Python wheels and sdists, the generated
Homebrew formula, the generated AUR PKGBUILD, Helm charts, Docker
SBOMs, aggregate dual-registry cosign receipts, and a SHA256 checksum
manifest.