--- source: raw/schema.sql content_hash: 71b47e47b483834c887de14c76d5b16506d90ad64198d76a92a7b3731132dab8 namespace: work last_synced: 2026-05-30 confidence: 0.9 tags: [personal-os, postgres, schema, asana] --- # Personal OS — Postgres Schema The Personal OS Postgres database holds Asana sync state, agent annotations, file references for wiki ingest, the LLM-synthesised wiki, and a semantic memory store. Extensions required: `vector` (pgvector) and `pg_trgm`. ## Core Asana tables ### `tasks` One row per Asana task GID; upserted on every sync. Tracks identity, due dates, completion, assignee, project, and a `source` enum that records how the task was discovered: - `my_tasks` — assigned to me, lives in a My Tasks section - `following` — I'm a follower (commented, CC'd) - `delegated` — I created it, someone else owns it - `project` — visible via a project I'm on, none of the above Bookkeeping columns: `fetched_at`, `stories_fetched_before` (cursor used so we only pull new stories), `raw_json` (fallback for unmodeled fields). Indexes cover `modified_at`, `due_on` (partial — incomplete only), `assignee_gid`, `source`, `completed`, and a trigram index on `name` for fuzzy match. ### `stories` Raw Asana event log per task. The key resource subtypes are `comment_added`, `assigned`, `due_date_changed`, `section_changed`, `dependency_added`, `attachment_added`, `marked_complete`. Both plain text and raw HTML are stored — HTML is needed to extract embedded task GIDs. ### `task_edges` Directed graph of relationships between tasks. `relation_type` covers `subtask`, `dependency` (blocked by), `dependent` (blocking), `project_sibling`, and `mention` (referenced inside a story). `related_gid` may not yet exist in `tasks`, so it's not a FK. ### `task_annotations` Agent-written notes about tasks. `annotation_type` is one of `irrelevant`, `watching`, `needs_action`, `snoozed`. `annotated_by` is `agent` or `user`. ### `sync_state` One row per logical sync stream (`my_tasks`, `following`, `delegated`, `project:{gid}`, `workspace_events`). Stores `cursor` (ISO timestamp or events `sync_token`) and `full_sync_at` so partial syncs can fall back to a full pull when needed. ### `task_embeddings` 1024-dim Voyage embedding per task, indexed via HNSW with cosine ops. ### `active_tasks` view Convenience view: non-completed tasks that aren't annotated `irrelevant` or currently snoozed. Ordered by source priority (my_tasks → delegated → following → project), then `due_on`, then `modified_at`. ## Phase 0 additions (April 2026) All core tables gained a `namespace TEXT NOT NULL DEFAULT 'work'` column — the three allowed values are `work`, `personal`, `family`. Applied via ALTER TABLE; documented as commented-out statements at the bottom of the file for fresh installs. `tasks` also gained `possibly_deleted BOOLEAN` and `last_seen_in_full_sync TIMESTAMPTZ` — used by `generate-status.js` to filter out tasks that have disappeared from Asana between full syncs. ## Wiki + file ingest tables ### `file_references` Tracks files and URLs that should be ingested into the wiki. Holds a macOS security-scoped `bookmark_data` BYTEA, `last_known_path` (resolved cache), optional `url`, `content_hash` (SHA256), `mime_type`, `title`, and a `modification_log` JSONB of `{ts, hash_before, hash_after}` entries. The `wiki_stale` flag drives whether the wiki-ingest prompt processes the file on its next run. ### `wiki_pages` LLM-synthesised wiki content (not raw copies). Columns: `namespace`, `title`, `content` (markdown), `sources` JSONB pointing back at `file_references`, `confidence`, `superseded_by` (chains old versions), `stale`, `last_synced_hash`, and a 1536-dim `embedding`. Tagged for ivfflat index but the index is held off until the table has 1000+ rows for usable recall. > Note: per Decision 8 in [[personal-os-state-2026-04-27]], the live > Personal OS no longer uses these DB tables for wiki ingest — the vault > is the source of truth and SHA256 lives in frontmatter. The tables > remain in the schema for compatibility / future re-use. ### `memory_store` Semantic memory accumulated from Discord, Claude sessions, and manual entries. `type` ∈ {`fact`, `preference`, `decision`, `person`}; `source` ∈ {`discord`, `claude`, `manual`}. Includes `entities` JSONB, `confidence`, `embedding` (1536), and an optional `expires_at` (NULL = permanent). ## Key Points - All namespaces gated to `work | personal | family` via CHECK constraints. - pgvector embeddings live on three tables: `task_embeddings`, `wiki_pages`, `memory_store`. Only `task_embeddings` ships with an HNSW index; the wiki/memory ivfflat indexes are commented out until data volume justifies them. - The `active_tasks` view is the canonical "what should I look at" surface for agents. ## Related [[personal-os-state-2026-04-27]] [[personal-os-catchup-plan-2026-04-27]] [[wiki-ingest-process]] [[ddg-asana-workflow]]