# Workflow system blueprint Status: authoritative design; discovery complete, implementation pending Last revised: 2026-09-05 This document is the source of truth for streamlining the workstation and the surrounding Yookr workflow. It records the intended system, the changes needed to reach it, the trials that must precede conditional decisions, and work that is deliberately deferred. Historical exploration and rejected alternatives are not retained unless they prevent a likely wrong turn. Remaining uncertainty is empirical rather than conceptual. Every unsettled choice below has a bounded pilot, a pass condition, and a fallback; it is not an invitation to resume general tool discovery. ## Governing intent Build a quiet, keyboard-first control plane over development, investigation, operations, agents, and personal knowledge. The goal is a small coherent set of interfaces, not one application pretending to do every job. The governing rules are: - Give each intention one canonical owner. A native CLI may remain as a troubleshooting substrate without becoming a second documented workflow. - Standardize vocabulary, entry points, and lifecycle boundaries. Do not force unlike workloads onto the same implementation merely for visual uniformity. - Put frequent actions on direct keys and make less frequent actions discoverable through the surface that owns them. - Keep stable packages, services, integration, and durable preferences under Nix. Keep application databases, caches, sessions, trust, credentials, and other mutable state with the application that owns them. - Prefer supported application layers and native file formats. Add adapters or wrappers only for a demonstrated gap. - Repositories own reproducible development context, executable project documentation, and artifacts specific to their code or schema. Global state is reserved for genuinely cross-project or personal material. - Select an environment per operation. Do not rely on a long-lived ambient production context. - Keep destructive or production actions more deliberate than navigation and read-only inspection. - Promote automation only after the underlying manual workflow has repeated and can be verified. A pilot is not yet a permanent abstraction. - Prefer maintained free and open-source software. A paid tool is acceptable only when it has an unusually strong, non-reproducible advantage. - Optimize conceptual complexity and review burden, not package count or line count in isolation. The principal vocabulary is: - scope: `work`, `own`, `ext`, or `forks`; - Yookr domain: a service/product repository, data science, `traceability-data-model`, or the cross-system `yookr-workbench`; - environment: exactly `local`, `test`, or `live`; - intention: develop, inspect, query, review, operate, or deploy; - status: **selected**, **pilot**, **retire after migration**, or **deferred**. These coordinates compose. They are not stages in a mandatory linear process. ### Explicit exception Credentials and `.env` files normally stay outside Git, the Nix store, and broad synchronization. The existing secret-bearing `yookr-vpn.ovpn` is a user-accepted exception: it may remain in Syncthing for use on Zenith and Polaris. Restrict the source file to the user where Syncthing permits, never print or commit its contents, and import it into each machine's root-owned NetworkManager connection store. Do not generalize this exception. ## Target ownership model | Intention | Canonical surface | Owner and status | | --- | --- | --- | | Find applications, projects, or open windows | Walker/Elephant | **Selected**; applications plus an Elephant Lua project menu | | Search personal passwords globally | Walker with `rbw` | **Selected** for personal Vaultwarden; company Bitwarden remains in its browser extension | | Navigate tabs, history, bookmarks, and browser commands | Vivaldi Quick Commands (`F2`) | **Selected**; Vivaldi remains the only bookmark authority | | Arrange windows and displays | Niri | **Selected**; dynamic workspaces and no application-specific display roles | | Work in a terminal | Kitty | **Selected**; no routine Kitty tiling or second terminal implementation | | Edit related files and views | Neovim | **Selected**; buffers and temporary splits, without automatic session restoration | | Enter a repository environment | `direnv` with `nix-direnv` | **Selected**; tracked `.envrc` and a default flake development shell | | Discover non-obvious project actions | `just --list` | **Selected** for participating repositories; recipes delegate to native tools | | Run actively edited first-party code | Native processes, optionally Process Compose | **Selected** for fast reload and debugger access | | Run a container-only repository stack | Rootless Podman Compose | **Selected**; foreground, explicit, and scoped to the work session | | Run a persistent containerized user service | Rootless Podman Quadlet | **Selected**; user systemd owns lifecycle and logs | | Run a durable host service | NixOS module and systemd | **Selected** when a maintained native module fits | | Exercise APIs | Kulala and `xh` | **Selected**; JetBrains-compatible `.http` files are the durable artifact | | Query databases | Dadbod and native driver CLIs | **Selected**; named machine-local connections and repository-owned queries | | Investigate across Yookr services | `yookr-workbench` | **Selected**, initially local to Zenith | | Connect the Yookr VPN | Noctalia Network control center | **Pilot** NetworkManager/OpenVPN migration; OpenVPN 3 remains the fallback until both hosts pass | | Inspect test Kubernetes | `just k8s test` to Gardenctl and `k9s` | **Selected**; isolated session and unchanged parent shell | | Inspect or operate RabbitMQ | Official management UI | **Selected**; `rabbitmqadmin` is the terminal fallback | | Browse S3-compatible storage | `rclone` | **Pilot**; explicit read/list/copy commands before interactive mutation surfaces | | Capture and find notes | `zk` through Neovim | **Selected**; one synchronized Markdown notebook and one daily intake path | | Present work/personal PIM on desktop | Evolution | **Pilot**; server authorities do not change during evaluation | | Present personal PIM on Android | DAVx5, aCalendar+, Google Contacts, Tasks.org | **Pilot**; the server authorities remain unchanged | | Give agents durable project context | `AGENTS.md` and project commands | **Selected**; concise facts, invariants, architecture pointers, and checks | | Run top-level interactive agents | Herdr | **Pilot** for persistence, attention state, notifications, and worktrees | | Maintain conversation state and internal subagents | Each native agent, primarily Codex | **Selected**; Herdr does not mirror internal subagents | | Review local changes | LazyGit in the task checkout | **Selected**; Git remains branch/worktree truth | | Review a pull request | `gh` for metadata/diff, then a review worktree when needed | **Pilot**; do not add another review application yet | ## Change program The phases below are dependency ordered. Each change appears once; trial details live in the evaluation section rather than being restated throughout the plan. ### Phase 1: reconcile state and ownership #### Repositories and paths - Before moving any repository, inspect its dirty state, linked worktrees, destination collisions, and authored path consumers. Move registered worktrees with `git worktree move` where possible and run `git worktree repair` after changing a repository root. Do not apply a broad filesystem move to unchecked repositories. - Reconcile the divergent dirty copies of `yookr-dashboard-new` under `~/sync` and `~/work/repos` before moving or deleting either. Establish the authoritative commit and preserve unique tracked, untracked, ignored, local data, and secret inputs deliberately. A general archive operation must not choose between these copies implicitly. - Consolidate source repositories under the existing XDG projects root: `~/dev/work/`. Do not keep the accidental `~/work` root, the intermediate `repos/` directory, or a permanent compatibility symlink. - Keep these work repositories active: `aggregation-api`, `prediction-api`, `rules-service`, `yookr-api`, `yookr-dashboard`, `yookr-dashboard-new`, `yookr-data-science`, `yookr-management-svelte-redo`, and `traceability-data-model` (currently `schemas`). Add `yookr-workbench` when its pilot begins. - Rename `schemas` to `traceability-data-model` during the move. Update authored path consumers; generated Codex, shell, and Herdr histories may remain historical. - Move every other repository from the current work inventory intact to `~/dev/work/.archive`. This includes `yookr-management-new`, `yookr-management-svelte`, `yookr-dashboard-new.old`, `pipelines.old`, `yookr-dashboard-new.zip`, `rules-service-hex`, `yookr-data-science-no-kedro`, and tutorial repositories. Do not infer active status from a product-looking name. - Archive the small `~/work/rabbitmq` scratch project. Remove the empty legacy `.data/mongodb` directory only after a final emptiness check; do not move the global `.data` directory into the source tree. - Make Git identity rules explicit and non-overlapping: work identity below `~/dev/work`, personal identity below `~/dev/own`, `~/dev/ext`, and `~/dev/forks`. Update the old `~/work` conditional include. - Treat work/personal labels as identity and navigation boundaries, not privacy boundaries. Non-secret work material may synchronize to the Pixel and Orion; source checkouts, credentials, and runtime state do not belong in the broad `~/sync` tree. - Remove stale path-bound Codex trust and obsolete approval entries after the move. Update the transitional Bruno workspace path only if Bruno still needs it during migration. #### Nix and mutable application state - Preserve the existing host/profile/capability structure, typed facts, flake-parts composition, Home Manager integration, and primary-tool indirection. No repository-wide architecture migration is justified. - Keep flakes and `nh os switch` as the normal activation path. Keep Neovim's Lua, wrapper, plugins, language servers, and formatters store-backed; accept the measured rebuild cost rather than adding an out-of-store fast path. - Do not prototype Hjem/Rum, replace flakes with `npins`, or add a separate Home Manager activation wrapper. These do not address the accepted ownership model. - Remove the unused `nixpkgs-stable` input and its dead local binding. Let Noctalia follow the root Nixpkgs input if the pinned configuration evaluates unchanged; describe this as dependency-graph hygiene, not a latency fix. - Retire or rewrite the stale root `PLAN.md` after checking whether it contains unfinished Neovim work. It must not continue to claim that Helix is active. - Keep Flatpak enabled as an intentionally available installation facility, but add no declarative Flatpak manager, remotes, or applications while it has no consumers. - Continue declaring Noctalia's stable policy through Nix. When behavior differs from the declaration, inspect its writable XDG state as a second supported application layer; keep only genuinely local runtime state there rather than adding another synchronization mechanism. #### Codex configuration ownership - Rotate the exposed Context7/MCP credential and replace plaintext headers with an environment-backed header or supported credential mechanism. - Generate stable Codex defaults at `/etc/codex/config.toml`: MCP endpoints, approval defaults, notifications when Codex owns them, and other durable cross-machine preferences. Official precedence makes this a lower-precedence default layer. - Leave `~/.codex/config.toml` writable and machine-local for project trust and unavoidable local settings. Review non-trust keys occasionally: promote a deliberate cross-machine preference to Nix, retain generated/machine state, and remove accidental overrides. Do not add a drift daemon. - Keep global `AGENTS.md`, intentional rules, and user-authored skills under Nix/Home Manager. Keep authentication, conversations, databases, caches, downloaded plugins/skills, and generated Herdr integrations untracked. - Remove the stale `~/.config/codex` tree; its preservation audit found no unique authored material worth migrating. ### Phase 2: establish the project contract and Yookr workbench #### Common repository contract Participating repositories expose the same concepts without copying an empty directory taxonomy: - A tracked `.envrc` enters the default flake development shell and selects only non-secret local defaults. Activation must not perform `uv sync`, start services, fetch data, or do other mutating/network work. - `flake.nix` owns reproducible dependencies, packages, checks, and the formatter. A flake app remains only when it is an actual runnable or distributable program. - `just --list` is the documented index of non-obvious human and agent tasks. Recipes delegate to native commands and omit trivial one-off operations; the native CLI remains available for diagnosis without becoming a second catalog. - Install `just` as a workstation bootstrap tool and include it in participating development shells so the repository remains portable. - `AGENTS.md` records architecture pointers, invariants, project commands, and required checks. It stays factual and concise; it does not duplicate generic global behavior. - Service-owned `.http` examples and schema-owned `.sql` files live beside the code or schema they describe. Generated views, caches, and scratch results are not durable sources. - Environment selection is per operation. Kulala selects a buffer environment, Dadbod selects a visibly named connection, and recipes accept an explicit argument such as `just k8s test`. - Secrets enter at runtime from the service's approved source or a user-only machine file outside all checkouts, initially `~/.config/yookr/.env`. A tracked `.envrc` may load that stable path with `dotenv_if_exists`. - A new worktree behaves like a fresh clone. Recreate dependencies, caches, generated files, and build output; do not copy ignored state from a main checkout. Require an explicit `direnv allow` for each worktree. - Do not pre-allocate branch-derived ports, databases, Compose projects, or container names. Add targeted isolation only after a real task exposes a collision. First prove this contract in `rules-service`, paired with the API workflow in `yookr-api` and the database workflow in `traceability-data-model`. Only after two repositories reveal genuinely repeated files should a small native Nix flake-template repository be extracted. Language-native initializers continue to own language source layout. Repository-specific corrections are part of the pilots: - In `rules-service`, add a README, flake, `.envrc`, `justfile`, and concise `AGENTS.md`; document the local run path; correct the obsolete environment example; use `test`, not `dev`, for the deployed test environment. Do not encode the transitional rollout as a durable `deploy` recipe. - In `traceability-data-model`, rename the repository and make destructive schema recreation an explicitly named reset action rather than the ordinary `dev` path. - In `yookr-data-science`, default ordinary fetching away from live, remove `uv sync` from shell activation, keep the deployable soil-moisture pipeline, and move only generic cross-system exploration to the workbench. - In `yookr-dashboard-new`, preserve the useful visible Process Compose lifecycle. Expose it through `just dev` when the project adopts the common contract instead of maintaining a workflow-only flake app in parallel. #### Workload lifecycle - Run actively edited first-party code natively. - Use Process Compose only for two or more native or mixed foreground processes that need one visible lifecycle, dependency graph, and log view. - Use rootless Podman Compose for a wholly containerized repository stack. Keep support stacks manual, foreground, and scoped to a work session; preserve named volumes between runs and make running state visible to Podman tools. - Use Quadlet for persistent containerized user services and NixOS modules for durable host services when a good module exists. Do not nest lifecycle tools merely to obtain another status screen. - Configure Podman's external Compose provider deterministically. Do not use Compose dotenv behavior as the secret contract. #### `yookr-workbench` Create a minimal `yookr-workbench` on Zenith before adding workbench-owned API, database, or Kubernetes commands. Keep it without a remote while proving its contents. It owns only cross-system work: - curated cross-service `.http` requests; - operational queries and MongoDB scripts that do not belong to one service; - explicit local/test investigation commands; - the Garden/Kubernetes entry point; - uv-managed Marimo analyses, disposable experiments, and report exports. It does not own service OpenAPI specifications, schema migrations, deployable model code, general bookmarks, RabbitMQ URLs, or copied application state. Scratch work is promoted to its nearest durable owner or deleted. Unrelated personal Dadbod scratch stays under XDG data. Use Marimo's Python files as the analysis source. Ignore raw/local data and scratch output. Share source notebooks with technical readers, self-contained HTML as the faithful general report, browser-produced PDF when the delivery channel favors it, and individual SVG/PNG files only when a figure is itself the deliverable. Do not add a notebook hub or report server. Production data may be used on a developer machine; this streamline adds no separate anonymization or local-retention policy. Raw datasets and secret-bearing output still remain outside Git and broad synchronization. #### API and database workflow - Make Kulala and `xh` the editor/CLI pair. Keep hand-curated `.http` files as durable examples; use `kulala-fmt` OpenAPI conversion only to seed a migration or produce a disposable view. - Commit non-secret `local`, `test`, and `live` metadata in `http-client.env.json`. Keep credentials in ignored `http-client.private.env.json` or runtime environment variables. Make `local` the default environment; keep test/live selection explicit and visible per buffer. Kubernetes being test-only does not remove explicit live HTTP access. - Use Yookr API as the first proof. Support the sibling service-owned `openapi.yaml` and ignored snapshots fetched from test/live `/full-api-docs/openapi.json`. Authenticate through ordinary login and run a harmless administrator-authorized read. - Compare local and network specifications semantically with `oasdiff`. A network refresh writes and validates an ignored cache; it never overwrites a checked-in contract automatically. Do not add timestamped archives or polling. - Add `just openapi` to a service only when that repository has a reproducible generation command. A service repository remains authoritative for its specification; the workbench does not collect copied specs. - Use Dadbod UI's machine-local named connection store, normally `~/.local/share/db_ui/connections.json`, instead of the current single `DATABASE_URL` assumption. Name entries `--`, for example `test-rules-mysql`, `test-prediction-mysql`, and `local-traceability-postgres`. - Support PostgreSQL, MySQL/MariaDB, and MongoDB while the migration requires all three. Keep relational artifacts as `.sql` and MongoDB artifacts in their native JavaScript format. Durable queries belong in repositories; DBUI saved queries are personal scratch. - Prefer read-only credentials for workbench inspection where available. Dadbod is not itself a safety boundary. Intentional schema or data mutations belong in an owning repository or an explicitly reviewed operation. - Populate connection URLs manually. Do not extract Kubernetes Secrets or build a Bitwarden-to-Dadbod translation layer before manual connection management demonstrates a real cost. #### Kubernetes, RabbitMQ, S3, and SharePoint - Install `networkmanager-openvpn` on Polaris and Zenith, import the accepted VPN profile separately as a root-owned connection with autoconnect disabled, give it the same visible name on both machines, and use Noctalia's built-in Network control center. Retain OpenVPN 3 until the migration gate passes on both hosts. - Package official `gardenctl` and `gardenlogin` releases through Nix, use the nixpkgs OIDC plugin, remove duplicate binaries from `~/.garden` and `~/.local/bin`, and replace handwritten Zsh initialization with `gardenctl rc zsh`. Keep Garden configuration and kubeconfigs mutable and private outside the store. - Implement `just k8s test` in the workbench. It creates a fresh `GCTL_SESSION_ID`, targets Garden `leafcloud-test`, project `ryxtdg8ydl`, shoot `test`, derives `KUBECONFIG`, and opens `k9s` in the foreground. The parent shell remains unchanged. Use explicit `kubectl --namespace` for exceptional terminal work; do not guess a namespace. - Do not expose live Kubernetes or a deploy command. Image construction and GHCR publication remain in GitHub Actions while the team release process is unresolved. - Use the official RabbitMQ management UI for inspection, publishing/getting, and purge. Put `https://test.rabbitmq.yookr.org` and `https://rabbitmq.yookr.org` in a Vivaldi operations bookmark folder with explicit test/live labels rather than duplicating them as workbench recipes or Walker actions. Keep `rabbitmqadmin` for exact terminal operations; purge remains visibly interactive. - Pilot one machine-local `rclone` S3 remote using the least-privileged available credentials. Begin with `lsd`, `lsjson`, `tree`, and explicit read/copy operations. Do not expose `rclone ncdu` initially because its interface also deletes and has no read-only mode. - Reuse `rclone`'s OneDrive backend for a later SharePoint browse/download pilot before considering a second SharePoint tool. Do not introduce continuous sync or a mount until the real access pattern and company consent are known. #### Pull-request review - Use `gh pr view` for metadata/checks and `gh pr diff` for a quick read-only review. - Create a dedicated review worktree when local navigation, tests, or agent assistance are needed, then use LazyGit in that checkout. - Add no PR dashboard or wrapper until repeated reviews expose a specific gap. ### Phase 3: simplify global navigation and desktop interaction #### Walker and project opening - Keep Walker/Elephant as the global discovery surface and Niri direct bindings for the most frequent intentions. Keep `z ` as the shell fast path; it is another invocation surface over the filesystem, not another catalog. - Use Elephant's native dynamic Lua menu support as `menus:projects`. Scan Git roots across `~/dev/work`, `~/dev/own`, `~/dev/ext`, and `~/dev/forks`; exclude `.archive` and every worktree root. Show one flat result set with scope labels. - Have each result invoke one Nix-owned `open-project` command. It opens an interactive Kitty shell at the repository root, starts Neovim, and returns to a usable prompt after Neovim exits. It restores no buffers, layouts, or services. - Treat `yookr-workbench` as an ordinary project result. Do not generate a desktop entry per repository or maintain a separate project registry. - Retain Elephant's shipped provider defaults/prefixes instead of copying them into Nix. Keep the current `?` Bitwarden prefix as the local exception. Clipboard and credentials remain prefixed; quiet navigation providers may participate in unprefixed search. - Do not include bookmarks in Walker until a maintained provider can read Vivaldi live. Elephant's one-time CSV import would create a second authority. #### Browser ownership - Keep one neutral Vivaldi profile. Work/personal cookie and history isolation has no demonstrated value; rename the misleading `Work` profile if visible. - Use Vivaldi Quick Commands for tabs, history, bookmarks, and browser commands. Keep vertical tabs. Do not initially add Vivaldi workspaces, pinned tabs, Web Panels, command chains, or another Chromium browser. - Keep Actual, WhatsApp, and Outlook as web apps. Vivaldi owns installation, identity, authentication, permissions, and sync. After capturing each app ID, Home Manager owns one stable desktop entry invoking current Vivaldi with `--profile-directory=Default --app-id=`; suppress the duplicate Vivaldi-generated launcher. Reuse the known Actual ID `ahoihnifhakgijcmjlhbcgehigihinlo` and WhatsApp ID `hnpfjngllnobngcgfapefoaidbinmjnm`; capture Outlook's ID after installing it. This prevents stale Nix-store paths. - Keep a small Speed Dial beginning with ChatGPT and the Yookr GitHub organization. Google remains the search engine rather than a bookmark. - Sync durable bookmarks/Speed Dials, supported settings, extensions, and web apps between Zenith and Polaris. Keep open tabs and history local. Passwords remain Bitwarden-owned. - Use Bitwarden's multi-account browser extension for personal Vaultwarden and company Bitwarden. Walker's `rbw` provider remains personal-only; do not copy company secrets, create another browser profile, or build a private adapter. #### Niri vocabulary - Design for two general-purpose displays with dynamic workspaces. Do not pin applications, roles, or content to a monitor. On Zenith, place the external widescreen to the right and focus it initially once its stable identity has been captured during a docked session. - Keep `Super+H/J/K/L` for focus and `Super+Alt+H/J/K/L` for frequent window/column movement. Keep `Super+U/I` for workspace navigation, the corresponding deliberate move/reorder operations, useful mouse-wheel bindings, and touchpad gestures. - Remove arrow-key duplicates, Page Up/Down aliases, numbered-workspace bindings, first/last-column jumps, centering, maximize-to-edges, direct compositor quit, monitor power-off, and the unused hotkey-overlay binding. - Remove the NixOS-config terminal, NixOS-switch, edit-secrets, and color-picker shortcuts and their shortcut-only scripts. Underlying terminal commands stay. - Consolidate screenshots on Niri's interactive `Super+S` UI. Keep `Super+O` overview, `Super+Q` close, and `Super+Ctrl+L` lock. - Keep `Super+R` preset width cycling, one incremental resize family, column maximize, and fullscreen. Retain stacking/consume-expel actions, tabbed columns, toggle floating, and focus switching between floating and tiling as secondary capabilities. - Replace the fragile mutable-index `Super+A` helper only through the bounded pilot below. Niri 26.04 actions accept a workspace index or name, not stable IPC workspace IDs, and have no atomic active-workspace swap. ### Phase 4: make the agent workflow coherent #### Context, skills, and client boundaries - Keep Codex primary and Claude Code/Pi as experimental fallbacks without fixed specializations or forced feature parity. - Share repository `AGENTS.md`, concise global guidance, project commands, user-authored skills where natively supported, and verified MCP endpoint facts. Keep client-specific model/UI settings, approvals, authentication, trust, and runtime state native. - Centralize MCP endpoint facts in the Nix AI capability only after Codex and Claude both consume them, then render thin native configurations. Pi has no native MCP owner and should not receive a wrapper for cosmetic parity. Remove generic Home Manager `programs.mcp` output if it remains unused. - Do not create a prompt-template menu or demonstration skills. Promote a procedure only after it has stable inputs, outputs, and verification. - Create the instruction-only `nixos-maintainer` skill as the first demonstrated candidate. It inspects repository instructions and the complete current owner, prefers native options and existing patterns, researches version-sensitive choices, keeps mutable state outside the store, makes focused idiomatic edits, formats them, and performs the smallest meaningful no-switch validation for affected hosts. Switching a generation requires a separate explicit request. Add scripts only after a deterministic repeated operation appears. #### Top-level agents and worktrees - Pilot Herdr as owner of top-level Codex, Claude, and Pi processes, cross-agent attention state, detach/reattach, desktop notifications, and the normal create/open/list/remove worktree flow. - Start or attach Herdr on demand. Do not add a supervised login service: the client already starts a persistent background session. Stop it deliberately with `herdr server stop`. Keep ordinary terminals, Neovim, dev processes, and LazyGit outside Herdr. - Configure Herdr as the sole notification owner during the pilot. If it fails, use Codex's built-in TUI notifications before an external notify command. - Use one workspace per active checkout or cross-repository investigation and one pane per top-level agent. Internal Codex subagents remain in Codex. - Let Herdr use Git worktrees as its substrate. For the first work-only pilot, place them under `~/dev/work/.worktrees//` and exclude that tree from Walker. Use an explicit path for other identity scopes until a scope-preserving convention is proven. - Do not install Worktrunk initially. Herdr 0.8.2 covers the proposed basic lifecycle and leaves branches intact for human review. Revisit Worktrunk only for demonstrated needs such as richer cross-worktree state, shell switching, CI/PR views, process cleanup, or integration-aware branch removal. Keep native `git worktree list`, `repair`, and `prune` as maintenance escape hatches. - Defer `codex agents`. Codex 0.153.4 exposes it, but local diagnostics show ephemeral app-server mode and daemon bootstrap that assumes a standalone managed install rather than the Nix-store binary. Do not add a second mutable Codex installation or custom daemon workaround. #### Task lifecycle - Use one primary writer per checkout. It may delegate bounded independent read-heavy work; concurrently running internal subagents do not edit the same checkout. Confirmed read-only investigations may share a checkout and need no branch or worktree. Sequence tasks expected to overlap in files or behavior. - Use `feat/-`, `fix/-`, or `chore/-`, omitting the issue when none exists. Reuse the slug for the checkout, Herdr label, and optional execution plan. - Keep setup explicit: create the worktree, review and authorize `.envrc`, then start the agent there. Do not add hooks, copy ignored files, launch agents from Walker, or hide these state changes in a wrapper. - Use Codex `/plan` when design is uncertain, then one `/goal` containing the outcome, constraints, and verification for substantial execution. A goal is a persistent target, not a milestone hierarchy. - For genuinely substantial multi-session work, keep one living `docs/plans/.md` in the branch and reference it from the goal. Record scope/non-goals, architectural facts, verifiable milestones, progress, discoveries, decisions, evidence, and the exact next step. Link to source instead of copying logs. Move lasting knowledge to normal docs/ADR at the end and delete a transient plan when it has no continuing value. - Let the primary agent make local commits at meaningful verified or resumption boundaries, not mechanically after every milestone. It does not push, merge, open a pull request, or mutate GitHub without an explicit request. - End on a checked, locally committed branch with a handoff covering outcome, verification, limitations, and unresolved decisions. Review with LazyGit in the task worktree. The user chooses publication, integration, revision, or abandonment; remove the checkout only afterward. ### Phase 5: consolidate notes, PIM, and transcription #### Notes and meeting knowledge - Consolidate both notebooks into `~/sync/notes` on one fully synchronized node with no concurrent writers. Preserve authored notes/images and merge the two `todo.md` files deliberately. Stop generating `~/sync/work/notes`. - Use `daily/YYYY-MM-DD.md` as the unclassified intake path, with no title prompt or required frontmatter. Use a `zk` group/alias for idempotent daily-note creation. Keep ordinary titled notes at the notebook root until use justifies another collection. - Bind unused `Mod+N` to a small Nix-owned command that opens today's note at the append position in a dedicated Kitty/Neovim window and closes with Neovim. - Store planned meetings as dated files under `meetings/` and raw transcripts separately under `transcripts/`. A person curates decisions/context into the meeting note. During the Monday development meeting, the team cooperatively decides and creates issues, which the meeting note then links. Agents do not create issues or automatically ingest transcripts into daily notes. - Keep Markdown/zk as notes authority. Personal actionable tasks belong in Radicale VTODO, private/email-derived work follow-ups in Microsoft To Do, and shared development work in GitHub issues. Link Markdown context instead of duplicating it into another task database. #### PIM authority and presentation - The PIM foundation must remain free of charge, with open-source components preferred. Paid services such as Morgen are excluded from this role. - Keep Microsoft 365 authoritative for work/university mail, calendar, people, and Microsoft To Do. Keep Radicale authoritative for personal CalDAV calendars/VTODO and CardDAV contacts. Clients may present both but do not copy data between authorities or create a bidirectional bridge. - Pilot Evolution with all four active mail identities: personal, old personal, university, and work. Use its Microsoft 365 account type for Microsoft identities, not legacy Exchange/EWS. Connect personal accounts and Radicale through native IMAP/SMTP, CalDAV, CardDAV, and VTODO. - Keep Thunderbird and the Outlook Vivaldi app throughout the pilot. Change no authority until consent and daily behavior pass. If Evolution passes its gate, make it the canonical desktop PIM and retire Thunderbird. Keep Outlook as the Microsoft-native fallback, not a second general PIM workflow. - Keep Radicale rather than adding Baikal or Nextcloud. A larger groupware stack does not solve Microsoft federation and no personal web UI is required. - On Android, use DAVx5 as the sole Radicale adapter. aCalendar+ and Google Contacts consume Android providers; Tasks.org consumes DAVx5/OpenTasks and may separately connect to Microsoft To Do. Do not configure Radicale twice. - Use free/F-Droid DAVx5 and Tasks.org builds. Account for Tasks.org's Microsoft To Do limits--partial recurrence, one reminder, no attachments, and no manual ordering--and give each collection one notification owner. Test Outlook's optional calendar/contact export and correct default accounts. - Before removing the last independent PIM copy, test restoration of Radicale collections and authentication data. Keep broader Orion backup redesign out of scope. #### Meeting transcription - Use Fossify Voice Recorder on the Pixel and Syncthing directly to Orion. Orion becomes the always-on transcription owner; this does not reopen general backup, CI, builder, or agent-offload design. - First observe a real recording transfer. Fossify writes directly to its final filename while recording, so a Syncthing/path event alone does not prove the meeting ended. Prefer an automatic post-record move to a dedicated inbox if available; otherwise require an unchanged size/mtime settlement period plus media readability/duration validation. - Once completion detection is proven, refactor the Zenith/Vulkan module for Orion's CPU `whisper-cpp` runtime and one inbox/processing/archive/failed tree. Use an event-triggered path/service pair to wake an idempotent scanner instead of polling every two minutes. - Keep the multilingual model and automatic language handling. Run diarization by default, but publish an unlabeled transcript when Whisper succeeds and diarization fails; record the partial failure instead of withholding it. - Write transcripts under `~/sync/notes/transcripts` and preserve originals in the recordings archive. The transcript is the quiet success signal; systemd state/logs expose failures. Add no desktop notification. - Validate with a Dutch/English meeting, preferably with code switching, and require completion by the next morning. Consider a GPU worker only if Orion misses that service level. Syncthing replication is not backup. ### Phase 6: retire duplicate applications and dead configuration Perform removals after the corresponding migration or pilot. - After valuable definitions are migrated, remove Postman, HTTPie, Posting, and Resterm. Keep Kulala and `xh`; keep Bruno only through the HTTP pilot and remove it if no indispensable capability appears. - Remove Rainfrog, dblab, Harlequin, Tabularis, DbGate, pgAdmin, Beekeeper Studio, MongoDB Compass, pgModeler, and tbls. Remove the Harlequin profile. Keep Dadbod and wrapper-local clients; keep DBeaver only through the database pilot and remove it if no GUI-only need emerges. - Remove global `usql` and MariaDB. Keep PostgreSQL, MariaDB, and `mongosh` only in the Neovim wrapper or repository environments that own them. - Search once for an application/plugin that shells out to npm. If found, declare Node with that owner; otherwise remove global Node.js and Bun and keep language runtimes in repository flakes. - Remove Zed and the inactive Helix module, cache settings, and flake input. Keep Neovim. Retain Jujutsu as a **deferred** experiment with no assigned workflow until a concrete use case exists. - Remove inactive Foot modules and keep Kitty as the only terminal. - Remove Obsidian, Planify, and Calcure after note/PIM ownership is in place; none owns data that needs migration. - If Evolution passes, remove Khal, Todoman, and local `pimsync`. Keep Noctalia as a read-oriented calendar glance surface. Add no terminal PIM client without a demonstrated operation. - Install Pinta beside GIMP for its bounded trial. Remove GIMP only if Pinta covers the workload; otherwise remove Pinta and retain GIMP. - Retain Spotify, OnlyOffice, Nautilus, imv, Sioyek, mpv, qBittorrent, and Discord. Keep Nautilus as graphical file manager/directory default and `xdg-desktop-portal-gnome` with GTK fallback as file chooser. Do not add Thunar, Dolphin, Nemo, or another file manager without a concrete gap. ## Evaluation gates ### Project contract and workbench Pass when a fresh checkout of each pilot repository can enter its environment, discover relevant commands, run checks, and reach a useful local state using only tracked configuration plus documented machine-local inputs. Confirm no shell activation mutates state and a new worktree reads no ignored files from another checkout. Extract templates only after two pilots share real boilerplate. Run two representative development servers and test suites concurrently using their native behavior. Continue deferring branch-derived ports, databases, and container-project names only if endpoints remain discoverable and no actual resource collision appears; otherwise add isolation only for the observed conflict. For the workbench, prove one authenticated Yookr API read, one named connection for every needed database engine, isolated `just k8s test`, and one Marimo-to-HTML report. Publish or expand it only after those artifacts confirm the boundary. ### Herdr and worktrees Exercise short and long Codex sessions, an approval-blocked session, detach/reattach, one Claude or Pi fallback, and two independently writing task worktrees. Evaluate runtime/attention, notifications, and worktree handling as separate components, retaining only those that pass. Attention state must be accurate, exactly one notification must be delivered, paths must be predictable, dirty removal must be refused, branches must remain for review, and layout overhead must cost less than the polling/navigation it replaces. If Herdr's runtime or notification role fails, retain native agent sessions and Codex TUI notifications. If its worktree role fails, use native `git worktree add/list/remove`; compare Worktrunk only after that ceremony becomes repeated friction. ### Agent conventions Test the instruction-only `nixos-maintainer` skill with representative prompts that add, change, remove, and diagnose a capability, plus unrelated prompts that must not trigger it. Pass when it follows repository ownership, makes focused edits, performs appropriate no-switch validation, and leaves switching to an explicit request. Separately, give a fresh Codex session only the repository, its `AGENTS.md`, and a living execution plan from a substantial paused task. Promote the convention only if it can identify the exact next step and resume correctly without chat history or copied logs. ### S3 and SharePoint On one real Yookr task, configure a machine-local, least-privileged S3 remote and prove target selection, listing, download, and an explicitly authorized upload without accidental mutation. Pass when native `rclone` commands are clear and auditable enough that no interactive browser is needed; otherwise remove the pilot configuration and package. Keep SharePoint deferred until company consent and a real browse/download case exist. ### Pull-request review gate Exercise one `gh pr view`/`gh pr diff` review and one review worktree with local navigation or tests. Pass when metadata, checks, local verification, LazyGit, and optional agent assistance are reachable without another review UI. If it fails, record the exact missing operation before evaluating one maintained alternative. ### Evolution and Android PIM Pass Evolution only after all four accounts prove send/receive, folder behavior, search, offline mail, invitations, recurrence exceptions, contacts/GAL, Microsoft To Do recurrence/reminders, and acceptable daily UX. Confirm tenant consent and one notification owner per collection. If it fails, retain Thunderbird plus Outlook PWA and keep Radicale clients native. On Android, prove two-way Radicale calendar/contact/task synchronization, Microsoft To Do within documented limits, clear collection labels, correct default accounts, recurrence, reminders, and Outlook export where permitted. If DAVx5 fails, keep personal Radicale data in the existing desktop/native clients and Outlook as the Microsoft 365 Android client. If only Tasks.org's Microsoft integration fails, keep Tasks.org for personal VTODO through DAVx5 and use Outlook for Microsoft tasks. Neither failure changes server authority. ### NetworkManager VPN Install `networkmanager-openvpn`, import the profile separately on Polaris and Zenith with autoconnect disabled, and use Noctalia's existing Network control center as the only desktop toggle. Pass after route, DNS, test-service access, suspend/resume, reconnect, and reboot work on both machines. Remove OpenVPN 3 only after both pass. ### Niri active-workspace exchange Pilot a two-output-only helper that assigns collision-free temporary names to both active workspaces, preserves original names, moves each named workspace to the other output, makes both arrivals active, restores names, and returns focus to the original physical output. It remains non-atomic and must restore names on failure where possible. Keep it only if repeated swaps are reliable and the visible transition is acceptable; otherwise retain the current shortcut temporarily and track a native Niri action rather than growing the wrapper. Capture Zenith's external display identity before encoding right-hand placement and initial focus. ### Pinta Reproduce recent edits covering clipboard/open, selection, crop/resize/canvas, text/drawing/shapes, layers/transparency, basic adjustments, and PNG/JPEG export. If every required operation works, select Pinta and remove GIMP. Otherwise remove Pinta and keep GIMP; do not retain both indefinitely. ### Transcription Observe whether Syncthing transfers a growing Fossify recording and prove the completion protocol before automation. Then validate one real Dutch/English meeting end to end: recording, completed-file detection, transfer, CPU transcription, diarization fallback, archive, and Markdown by the next morning. Remove Zenith's timer only after Orion passes. ### Stable web-app launchers Capture the Outlook app ID, replace stale generated launchers for Actual and WhatsApp, and verify every Walker result starts current Vivaldi with the intended app/profile after a NixOS upgrade and Vivaldi Sync cycle. Expose one launcher per app. ## Deferred work - Design the team release process: intentional releases, immutable commit-addressed images, explicit revision promotion, rollout verification, rollback evidence, and Kubernetes-native base/overlay composition before a heavier GitOps platform. Do not encode mutable `:latest` rollout as a canonical workstation action. - Establish service-owned OpenAPI generation, publication, provenance, and consumer-refresh policy. Existing local/network drift calls for review, not automatic overwrite. - Adopt a company-wide infrastructure secret source when Yookr chooses one. Until then, keep manually supplied machine-local inputs and do not assume that Bitwarden Secrets Manager is available merely because Password Manager is. - Publish `yookr-workbench` privately when sharing becomes useful; do not create a temporary synchronization path. - Pilot SharePoint browse/download through `rclone` after Microsoft consent is known. Continuous sync and mounts require a separate demonstrated need. - Revisit Walker bookmark search only with a live Vivaldi reader, and company credential search only with maintained multi-vault support or repeated cost. - Revisit Worktrunk only after a concrete Herdr worktree gap. Revisit `codex agents` after Nix-managed daemon startup works without a second mutable installation. - Build a formal agent evaluation harness only after representative tasks and concrete configurations exist. Compare repeated runs on correctness, human intervention, review burden, conceptual complexity, wall time, and token use; structured agent output is telemetry, not the quality judgment. Controlled Codex evaluations consume `codex exec --json`; they never parse the interactive TUI or mutable internal databases. - Add Walker-to-agent launching only after the explicit Herdr/worktree sequence becomes repetitive enough to define a stable contract. - Keep remote Herdr, builders, CI runners, agent offload, and general Orion backup redesign out of scope until a concrete bottleneck justifies them. - Add a report server, notebook hub, Nextcloud groupware/Notes, terminal PIM client, or meeting-summary skill only after a missing capability is proven. - Add branch-derived ports, databases, container projects, or other concurrency isolation only after an observed resource collision. - Add LocalSend, OCR, dictation, global clipboard remapping, a second hotkey-help surface, or other distribution-inspired conveniences only after repeated use gives them a clear owner. ## Reference baseline Implementation must recheck fast-moving interfaces against the pinned version. - Projects: [Nix flake templates](https://nix.dev/manual/nix/latest/command-ref/new-cli/nix3-flake-init), [nix-direnv](https://github.com/nix-community/nix-direnv), [just manual](https://just.systems/man/en/), [Podman Compose](https://docs.podman.io/en/latest/markdown/podman-compose.1.html), [Quadlet](https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html), [Marimo](https://docs.marimo.io/). - APIs/data: [Kulala environments](https://kulala.app/usage/environments), [Kulala](https://github.com/mistweaverco/kulala.nvim), [Dadbod](https://github.com/tpope/vim-dadbod), [Dadbod UI](https://github.com/kristijanhusak/vim-dadbod-ui/blob/master/doc/dadbod-ui.txt), [RabbitMQ management](https://www.rabbitmq.com/docs/management), [rclone S3](https://rclone.org/s3/), [rclone OneDrive/SharePoint](https://rclone.org/onedrive/). - Desktop: [Walker providers](https://walkerlauncher.com/docs/providers), [Elephant menus](https://github.com/abenz1267/elephant/tree/master/internal/providers/menus), [Vivaldi web apps](https://help.vivaldi.com/desktop/miscellaneous/progressive-web-apps/), [Vivaldi Sync](https://help.vivaldi.com/desktop/tools/sync/), [Niri IPC](https://niri-wm.github.io/niri/IPC.html), [Niri actions](https://niri-wm.github.io/niri/niri_ipc/enum.Action.html), [Pinta guide](https://www.pinta-project.com/user-guide/). - Agents: [Codex configuration precedence](https://learn.chatgpt.com/docs/config-file/config-basic#configuration-precedence), [Codex long-running work](https://learn.chatgpt.com/docs/long-running-work), [Codex subagents](https://learn.chatgpt.com/docs/agent-configuration/subagents), [Codex notifications](https://learn.chatgpt.com/docs/config-file/config-advanced#notifications), [Herdr configuration](https://herdr.dev/docs/configuration/), [Herdr CLI](https://herdr.dev/docs/cli-reference/), [Git worktrees](https://git-scm.com/docs/git-worktree), [Worktrunk](https://worktrunk.dev/). - PIM/knowledge: [Evolution account types](https://help.gnome.org/evolution/intro-account-types.html), [Evolution Microsoft 365 implementation](https://gitlab.gnome.org/GNOME/evolution-ews/-/tree/master/src/Microsoft365), [Radicale](https://radicale.org/v3.html), [DAVx5](https://manual.davx5.com/introduction.html), [Tasks.org with DAVx5](https://tasks.org/docs/sync_davx5/), [Tasks.org Microsoft To Do](https://tasks.org/docs/sync_microsoft/), [`zk` daily journal](https://github.com/zk-org/zk/blob/main/docs/tips/daily-journal.md). - Infrastructure: [Gardenctl v2](https://gardener.cloud/docs/gardenctl-v2/), [NetworkManager `nmcli`](https://networkmanager.pages.freedesktop.org/NetworkManager/NetworkManager/nmcli.html), [NetworkManager keyfiles](https://networkmanager.dev/docs/api/latest/nm-settings-keyfile.html), [Syncthing synchronization](https://docs.syncthing.net/users/syncing), [Fossify recorder implementation](https://github.com/FossifyOrg/Voice-Recorder/blob/main/app/src/main/kotlin/org/fossify/voicerecorder/services/RecorderService.kt).