updates
This commit is contained in:
1 parent
f164d8b76e
commit
5748b3409b
60 files changed
+1346
-590
No files matched your search
@@ -1,19 +1,9 @@
|
|||||||
# Working in this repository
|
# Working in this repository
|
||||||
|
|
||||||
Read [the design](docs/design.md) and [current work](docs/current-work.md) before
|
Read [the design](docs/design.md) and [current work](docs/current-work.md) for
|
||||||
continuing the foundation pass. [README.md](README.md) maps configuration owners
|
repository decisions and active work. [README.md](README.md) maps configuration owners
|
||||||
and maintenance entry points. Global instructions remain applicable.
|
and maintenance entry points. Global instructions remain applicable.
|
||||||
|
|
||||||
- Keep design discussion and shared decisions in the main conversation. Discuss
|
|
||||||
two to four related choices with evidence, a recommendation, and alternatives.
|
|
||||||
Ask before changes to architecture, terminology, ownership, dependencies,
|
|
||||||
persistent data, user-visible behavior, or durable workflows. Implement routine
|
|
||||||
consequences of an accepted batch without repeated confirmation.
|
|
||||||
- Use subagents only for bounded, independent work when coverage or context benefits
|
|
||||||
justify it. No fixed team or delegation pattern is required.
|
|
||||||
- The pass covers existing or clearly intended capabilities. Consult relevant parts
|
|
||||||
of `~/sync/notes/setup-todo.md` as evidence, not authorization or a backlog.
|
|
||||||
Do not edit that note without an explicit request.
|
|
||||||
- Preserve unrelated changes. Coherent local commits are allowed for agreed batches.
|
- Preserve unrelated changes. Coherent local commits are allowed for agreed batches.
|
||||||
Do not push or make other remote changes without explicit approval. System
|
Do not push or make other remote changes without explicit approval. System
|
||||||
activation remains user-owned.
|
activation remains user-owned.
|
||||||
@@ -30,5 +20,3 @@ and maintenance entry points. Global instructions remain applicable.
|
|||||||
- Replace superseded state in `docs/current-work.md`; keep durable rationale in
|
- Replace superseded state in `docs/current-work.md`; keep durable rationale in
|
||||||
`docs/design.md` and operational detail beside its owner. Use Git for chronology.
|
`docs/design.md` and operational detail beside its owner. Use Git for chronology.
|
||||||
Remove temporary state when it no longer serves a purpose.
|
Remove temporary state when it no longer serves a purpose.
|
||||||
- Do not declare the pass complete unilaterally. Present the resulting model,
|
|
||||||
changes, evidence, and deferrals, and ask whether another area needs attention.
|
|
||||||
@@ -5,9 +5,10 @@ NixOS and Home Manager are composed through flake-parts and import-tree.
|
|||||||
|
|
||||||
## Start here
|
## Start here
|
||||||
|
|
||||||
- [Design](docs/design.md): vocabulary, ownership, and rationale.
|
- [Design](docs/design.md): vocabulary, ownership and coding conventions.
|
||||||
- [Agent instructions](AGENTS.md): repository collaboration boundaries.
|
- [Agent instructions](AGENTS.md): essential collaboration boundaries.
|
||||||
- [Current work](docs/current-work.md): accepted scope, open decisions, and next step.
|
- [Current work](docs/current-work.md): implementation state, pending decisions and
|
||||||
|
remaining acceptance checks.
|
||||||
|
|
||||||
## Configuration map
|
## Configuration map
|
||||||
|
|
||||||
@@ -15,76 +16,78 @@ NixOS and Home Manager are composed through flake-parts and import-tree.
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| Hosts | `modules/hosts/<host>/` | Identity, hardware, machine-specific selection |
|
| Hosts | `modules/hosts/<host>/` | Identity, hardware, machine-specific selection |
|
||||||
| Profiles | `modules/profiles/` | Combinations of capabilities |
|
| Profiles | `modules/profiles/` | Combinations of capabilities |
|
||||||
| Capabilities | `modules/capabilities/` | Behavior and integration across NixOS and Home Manager |
|
| Capabilities | `modules/capabilities/` | Behavior and NixOS/Home Manager integration |
|
||||||
| Facts | `modules/facts.nix` | Shared identity and topology; host facts are declared with hosts |
|
| Facts | `modules/facts.nix` | Shared identity/topology; host facts live with hosts |
|
||||||
| Composition | `flake.nix`, `modules/flake-parts.nix` | Inputs, discovery, host construction |
|
| Composition | `flake.nix`, `modules/flake-parts.nix` | Inputs, discovery, host construction |
|
||||||
| Secrets | `modules/secrets/` | Existing SOPS declarations and encrypted data |
|
| Secrets | `modules/secrets/` | SOPS declarations and encrypted documents |
|
||||||
|
|
||||||
Discovery makes named modules available; imports select them. Underscore-prefixed
|
Discovery makes named modules available; imports select them. Flat owners use
|
||||||
helpers and directories are excluded from automatic discovery and imported explicitly.
|
`name.nix` or `name/default.nix`. Private Nix helpers live under `_support/`, excluded
|
||||||
Add shared behavior to its capability and select it through the relevant profile.
|
from discovery. Scripts, assets and operational notes stay beside their owner.
|
||||||
Keep machine differences in hosts. A capability can own system and user modules.
|
Select shared behavior through profiles; keep machine differences in hosts.
|
||||||
|
|
||||||
The primary editor is selected in `host-base.nix`, the primary terminal in
|
The primary editor is selected in `host-base.nix`, the terminal in
|
||||||
`workstation-base.nix`. `modules/capabilities/theme.nix` selects the complete theme;
|
`workstation-base.nix`. `capabilities/theme/default.nix` selects Kanagawa;
|
||||||
Kanagawa lives in `modules/capabilities/_themes/kanagawa.nix`. Appearance belongs
|
application appearance lives in `theme/_support/`, interaction with capabilities.
|
||||||
there; interaction and layout belong with the capability.
|
|
||||||
|
|
||||||
## Work environment (provisional)
|
Both workstations import the provisional `work` profile. See
|
||||||
|
[workbench setup](modules/capabilities/workbench/README.md) for native devenv,
|
||||||
Both workstations import `modules/profiles/work.nix`: company network/development
|
company credentials and always-available read-only mounts. Only company-root and
|
||||||
integration, Garden tools, and work Git settings. This is a trial boundary, not
|
workbench environments are migrated; product/personal projects remain user-owned.
|
||||||
an independent workstation variant. SharePoint remains Zenith-only for now.
|
|
||||||
|
|
||||||
The tools-only environment is owned by
|
|
||||||
`modules/capabilities/yookr-dev/environment.nix`. It shares Garden definitions in
|
|
||||||
`_packages.nix` with installed tools and uses the system's nixpkgs pin:
|
|
||||||
|
|
||||||
```console
|
|
||||||
nix develop --quiet ~/.config/nixos#workbench --command bash --norc
|
|
||||||
```
|
|
||||||
|
|
||||||
This does not clear inherited credentials; start from a clean environment for
|
|
||||||
agent work. It does not load secrets, mount storage, or install Python dependencies.
|
|
||||||
Workspace `.envrc` files select it; the workbench's human credential and mount
|
|
||||||
steps remain workspace-owned. Requests, queries, analysis, and `uv.lock` stay there.
|
|
||||||
After loader changes, the user must review and re-allow the changed `.envrc` files
|
|
||||||
with direnv. No loader is sourced as part of validation.
|
|
||||||
|
|
||||||
## Maintenance
|
## Maintenance
|
||||||
|
|
||||||
Run from this repository:
|
|
||||||
|
|
||||||
```console
|
```console
|
||||||
just validate # format, evaluate, build every host and the workbench
|
just validate # format, evaluate, build all hosts and workbench tools
|
||||||
just validate polaris # same workflow, build only the named host(s)
|
just validate polaris # same workflow, build only the named host(s)
|
||||||
|
nix flake update # update inputs; selective input updates are also supported
|
||||||
```
|
```
|
||||||
|
|
||||||
The command includes current tracked files and non-ignored new files, respects
|
Validation copies current tracked and nonignored new files into a temporary snapshot,
|
||||||
working-tree deletions, and never changes the Git index. It resolves the pinned
|
respecting deletions and leaving the Git index untouched. It formats included Nix
|
||||||
formatter from a temporary source snapshot, formats included Nix files in the
|
files in the working tree, refreshes the snapshot, prepares devenv's upstream
|
||||||
working tree, then refreshes the snapshot for evaluation and builds. Ignored
|
evaluation dependencies, evaluates configurations and builds. Avoid concurrent edits:
|
||||||
untracked files and `.git` are excluded. Avoid concurrent edits during validation:
|
results describe that snapshot. Ordinary Git-backed flake commands outside the
|
||||||
results describe the snapshot, not subsequent changes.
|
wrapper still require new source files to be added to Git.
|
||||||
|
|
||||||
Output is limited to stage results and a short excerpt on failure. Full logs remain
|
Read the short result first. Full logs live in the printed `/tmp/nixos-validate-*`
|
||||||
in the printed `/tmp/nixos-validate-*` directory; source snapshots are removed on
|
directory. Failure stops the command; snapshots are removed on exit. It neither
|
||||||
exit. Failed stages stop the command. Inputs are not updated, no result links are
|
updates inputs nor creates result links or activates systems. The implementation is
|
||||||
created, and nothing is activated. Host names are discovered from the flake.
|
`scripts/validate.py`; `just` and Python are installed on both workstations.
|
||||||
|
|
||||||
`just` and Python are already declared for both workstations. The implementation
|
Use targeted hosts during iteration and full validation for a completed batch.
|
||||||
is `scripts/validate.py`; the justfile is only its entry point. The formatter output
|
Documentation-only changes need review and `git diff --check`, not system builds.
|
||||||
currently targets this repository's sole system, `x86_64-linux`.
|
Build, activation and interactive behavior are separate evidence.
|
||||||
|
|
||||||
Use full validation after a configuration batch and targeted hosts during iteration.
|
User-owned activation:
|
||||||
Documentation-only edits need review, local link checks, and `git diff --check`,
|
|
||||||
not system builds. Evaluation, build, activation, and confirmed behavior are
|
|
||||||
separate evidence. Outside this wrapper, ordinary Git-backed flake commands still
|
|
||||||
require intended new files to be added to Git.
|
|
||||||
|
|
||||||
The user activates with `nh os switch`. Edit encrypted data with
|
```console
|
||||||
`sops edit modules/secrets/secrets.yaml`; keep plaintext out of Nix expressions
|
nh os switch
|
||||||
and the store. No new credential-delivery design is selected yet.
|
nixos-rebuild switch --target-host orion --sudo --flake ~/.config/nixos
|
||||||
|
```
|
||||||
|
|
||||||
Historical material under `docs/.archive/` is evidence, not current instructions
|
Edit system ciphertext with `sops edit modules/secrets/secrets.yaml`; company
|
||||||
or a backlog. Consult it only for relevant unresolved questions.
|
provisioning is documented with workbench. Never put plaintext secrets in Nix.
|
||||||
|
|
||||||
|
## First-use acceptance
|
||||||
|
|
||||||
|
- **Notes:** Super+N and Walker's Notes open the same picker. Enter opens a note;
|
||||||
|
Ctrl+E creates one using the search text. Daily-note commands remain available.
|
||||||
|
- **Orientation:** Super+Shift+N names the focused workspace; submit an empty name
|
||||||
|
to clear it. Named empty workspaces persist until cleared. Noctalia shows labels;
|
||||||
|
terminal titles include the working directory and command.
|
||||||
|
- **Icons/vault:** check Oil from Walker and Nautilus device/symbolic icons. Walker's
|
||||||
|
`?` vault provider should request unlocking on use, never during desktop startup.
|
||||||
|
- **Calendar:** in Noctalia Settings → Services → Calendar, set the Radicale
|
||||||
|
password through the existing Personal account (GNOME Keyring). Add an ICS account
|
||||||
|
named Work using Outlook's published URL. Keep this URL in writable Noctalia
|
||||||
|
settings, outside this repository. Check both agendas; edit work events in Outlook.
|
||||||
|
- **Tailnet:** run `sudo tailscale up` on each machine and enroll the phone with
|
||||||
|
the Tailscale app. Keep Tailscale SSH disabled; use ordinary SSH keys. With
|
||||||
|
MagicDNS enabled, verify `ssh kiri@orion.<tailnet-name>.ts.net` from a workstation.
|
||||||
|
Existing `ssh orion` still uses the public address until the private route is
|
||||||
|
accepted. Close public Orion SSH only in the subsequent verified transition.
|
||||||
|
|
||||||
|
No systems have been activated as part of this implementation. Old SharePoint
|
||||||
|
mirror content, experimental AI data and unrelated workspace changes are preserved.
|
||||||
|
Historical material under `docs/.archive/` is evidence, not current authority.
|
||||||
+123
-66
@@ -1,78 +1,135 @@
|
|||||||
# Current work
|
# Current work
|
||||||
|
|
||||||
## Scope and accepted decisions
|
## Phase and working method
|
||||||
|
|
||||||
Foundation pass started 2026-09-19. Improve existing capabilities through discussion
|
Implementation is authorized and underway. Do not restart the broad design pass or
|
||||||
and coherent implementation batches; completion requires the user's agreement.
|
reconfirm accepted choices. `docs/design.md` owns the model, decisions and coding
|
||||||
|
conventions; README owns navigation/maintenance; operational details live with owners.
|
||||||
|
|
||||||
Accepted: retain host/profile/capability/facts composition and explicit ownership;
|
Complete independent agreed work and obvious fixes autonomously. Leave consequential
|
||||||
Polaris and Zenith have identical intended use; use the four-file harness. Validation
|
unknowns pending and collect recommendations/alternatives into one substantial review
|
||||||
uses a Git-ignore-aware snapshot without index changes, prioritizing low token cost.
|
batch. Ask earlier only to prevent broad rework/blockage. The old 2–4-question quota
|
||||||
The work profile is explicitly provisional. Consolidate the workbench environment
|
is superseded. Keep effort focused; no speculative systems or peripheral research.
|
||||||
only, using the shared NixOS nixpkgs pin; authored material and the Python lock stay
|
Do not activate, push, decrypt for discovery or access company systems with write
|
||||||
in the writable workbench. See [design](design.md) for durable boundaries.
|
authority. No subagents unless explicitly authorized by current instructions.
|
||||||
|
|
||||||
## Completed and evidence
|
Keep this record current by replacing superseded state. Pass-specific procedures
|
||||||
|
stay here, not in AGENTS. The user must agree before the overall pass is complete.
|
||||||
|
The unedited `~/sync/notes/setup-todo.md` remains an idea inbox, not authorization.
|
||||||
|
|
||||||
- Replaced Constellation with the four-file harness after preserving useful knowledge;
|
## Implemented, reviewed and validated; awaiting user checkpoint
|
||||||
older archives remain historical sources. Survey began from clean `3c022ad` on Polaris.
|
|
||||||
- Implemented `just validate` with optional host arguments. Full runs format, evaluate,
|
|
||||||
build all hosts, and now build the workbench shell. Logs are brief; details remain
|
|
||||||
in `/tmp`. The index is untouched by validation. Both prerequisites were already
|
|
||||||
declared on workstations.
|
|
||||||
- Added provisional `modules/profiles/work.nix`, imported by both workstations.
|
|
||||||
It selects existing VPN/development integration, Garden tools, and work Git settings.
|
|
||||||
Generic development/editor tools remain shared; SharePoint remains Zenith-only.
|
|
||||||
- Garden definitions now have one owner in `yookr-dev/_packages.nix`, used by both
|
|
||||||
installed tools and `devShells.x86_64-linux.workbench`. Preserved the workbench's
|
|
||||||
tools and Python variables; its nixpkgs pin now follows the system as agreed.
|
|
||||||
- Updated `~/yookr/.envrc` and `~/yookr/workbench/.envrc` to select the shared
|
|
||||||
environment; updated workbench README/instructions and removed its redundant
|
|
||||||
flake/lock. Its credential/mount body is unchanged. Requests, queries, analysis,
|
|
||||||
Python lock, existing changes, and generated data remain in place. Pre-change
|
|
||||||
migration files: `/tmp/workbench-environment-before-6k4dwzuo`.
|
|
||||||
- Full validation passed formatting, evaluation, Orion/Polaris/Zenith builds, and
|
|
||||||
workbench shell build on 2026-09-19. Logs: `/tmp/nixos-validate-4ojjb2q7`.
|
|
||||||
The existing unknown `modules` output warning remains. Whitespace review passed
|
|
||||||
in both repositories; loader changes were compared against pre-change copies.
|
|
||||||
No tests, activation, credential loading, mounts, or remote changes.
|
|
||||||
|
|
||||||
## Next step and user-owned actions
|
- Flat capability owners; service category flattened. AI, theme, Handy and
|
||||||
|
transcription support colocated. Imported Nix helpers moved under `_support/`.
|
||||||
|
File management owns Nautilus/GVfs/udisks; keyring remains separate.
|
||||||
|
- Removed Walker project discovery, agent-deck/notify, tmux, Zellij, TeamViewer and
|
||||||
|
direnv. Removed the uninstalled nixos-maintainer skill source. Retained Herdr,
|
||||||
|
Ollama/grounded-docs and their data, mail/calendar tools, dictation/transcription.
|
||||||
|
- Shared notes launcher uses Kitty's explicit directory and native zk note picker;
|
||||||
|
the picker already supports Ctrl+E creation. Oil's mini.icons provider loads
|
||||||
|
before initial directory buffers. Manual workspace naming/clearing and visible
|
||||||
|
Noctalia labels; shell titles include directory/command. Garden shell initialization
|
||||||
|
now belongs to company integration instead of every host's generic shell.
|
||||||
|
- Kanagawa declares Adwaita/hicolor icon fallback; modest Limine branding/layout.
|
||||||
|
A pinned Elephant patch defers its startup `rbw list` to the explicit vault query.
|
||||||
|
- GitHub devenv 2.3.2 installed with native Zsh hook and upstream reload defaults.
|
||||||
|
CLI dependencies keep upstream pins/cache; workbench tools use this repository's
|
||||||
|
exact nixpkgs pin. Company tools are also installed through the work profile. Product and
|
||||||
|
personal environments are untouched. No external loader was sourced or changed.
|
||||||
|
- Workbench runtime SecretSpec export helper resolves company/live/test independently,
|
||||||
|
clears stale owned variables, reports value-free status, and supports tools-only
|
||||||
|
entry/retry. Source mappings/provisioning remain pending below.
|
||||||
|
- User-run encrypted company migration helper prepared, never run. Company document
|
||||||
|
absent until user provisioning. Test mapping and login remain deliberately
|
||||||
|
unimplemented until the concrete context and plugin are known; the loader accepts
|
||||||
|
only an explicit noninteractive runtime snapshot. No company credential values
|
||||||
|
have been read.
|
||||||
|
- Both workstations select persistent read-only OBS/SharePoint user mounts, no content
|
||||||
|
cache; replaced Zenith-only hourly mirror. Existing data is preserved. Credentials,
|
||||||
|
old OBS mount handover and runtime acceptance remain user-owned.
|
||||||
|
- Tailscale enabled on all hosts; ordinary SSH keys retained. Zenith SSH is tailnet-only,
|
||||||
|
Polaris LAN SSH unchanged, Orion public SSH unchanged pending verification.
|
||||||
|
- Documentation consolidated; coding conventions in design, short AGENTS retained.
|
||||||
|
Validation prepares upstream devenv's import-from-derivation dependencies before
|
||||||
|
read-only flake checking, accepts the repository's declared official cache, and
|
||||||
|
reports interruption concisely. Full builds still include the tools-only shell.
|
||||||
|
|
||||||
User reviews and re-allows the two changed `.envrc` files with direnv, and activates
|
## Decisions/provisioning still needed
|
||||||
NixOS when ready. Do not run those loaders as an agent. The workbench retains
|
|
||||||
unrelated uncommitted analysis, documentation, and mount-helper work; do not commit
|
|
||||||
that work as part of this pass. Replicate the two loader changes and removal of the
|
|
||||||
old environment definition on Zenith; only Polaris's workspace was changed here.
|
|
||||||
|
|
||||||
Evaluate the provisional work boundary in practice, then discuss secret delivery.
|
1. **Company-root activation.** Native devenv suppresses its hook inside an active
|
||||||
Current constraints: human workbench entry exposes both test/live credentials and
|
devenv shell, including nested projects. No root environment is generated now;
|
||||||
starts read-only object-storage mounts; the tools-only environment does neither
|
recommend globally installed company tools at root and autoactivation only in
|
||||||
but does not erase inherited credentials. SOPS is already used, with different
|
workbench. This avoids custom activation machinery; confirm at the user checkpoint.
|
||||||
key locations for system and company material. No credential values were read.
|
2. **Test SecretSpec mapping.** Need the explicit test context and existing application
|
||||||
Clarify encrypted-file/key distribution across machines before proposing changes.
|
Secret/namespace/key coordinates (metadata only, no values). Confirm whether
|
||||||
Devenv and secretspec remain candidates, not dependencies. No new live authority
|
database Secrets hold complete URLs or separate components. Do not invent keys,
|
||||||
or per-connection launchers are authorized.
|
silently use the current context or fall back to live/SOPS test credentials.
|
||||||
|
Test loading reports unavailable until its runtime manifest and login snapshot exist.
|
||||||
|
3. **Explicit-login mechanism.** Final review removed the generic ExecCredential
|
||||||
|
interpreter: it duplicated a security-sensitive Kubernetes client protocol before
|
||||||
|
the actual company plugin was known. Inspect the selected context's exec stanza,
|
||||||
|
then choose its native/provider-specific cached login flow and prepare a mode-0600
|
||||||
|
runtime snapshot. Shell entry must not launch authentication.
|
||||||
|
4. **Live MariaDB certificate verification.** The migration helper preserves the
|
||||||
|
old `ssl-verify-server-cert=0` behavior. Before running it, either explicitly accept
|
||||||
|
that legacy risk or identify the correct CA/hostname settings and enable verification.
|
||||||
|
5. **Manual provisioning/acceptance.** Company SOPS recipients/migration, rclone
|
||||||
|
OAuth on both hosts, old OBS mount handover, devenv trust/responsiveness, Noctalia
|
||||||
|
Radicale password and private Outlook ICS URL, tailnet enrollment/private SSH.
|
||||||
|
See workbench README and root README. Do not close public Orion SSH yet.
|
||||||
|
6. **Guidelines review.** Design now spells out owner naming, module selection,
|
||||||
|
helper placement, package reuse/pinning, runtime boundaries and validation. No new
|
||||||
|
test policy, automation framework or pass-specific repo-wide rules were added.
|
||||||
|
|
||||||
## Questions to carry into relevant areas
|
## Validation state
|
||||||
|
|
||||||
- Desktop integration: terminal/launcher interfaces have inconsistent consumers;
|
Final full validation passed before the final review deletions:
|
||||||
Mailspring coexists with Thunderbird account declarations; Herdr coexists with
|
`/tmp/nixos-validate-t7zv1zux` (session 88912,
|
||||||
agent-deck notifications and multiple session tools. Determine purpose before
|
completed exit 0). Formatting, devenv preparation, flake check, all three host
|
||||||
removing anything. The disabled nixos-maintainer skill's source remains.
|
builds (Orion, Polaris, Zenith), and the tools-only workbench build passed.
|
||||||
- Cross-host behavior: earlier workspace migration was reported only on Zenith.
|
This includes the final notes startup ordering, serialized vault-query patch,
|
||||||
Verify Polaris paths before assuming equivalent filesystem state. TeamViewer and
|
FUSE wrapper paths, native Zsh retry function and SecretSpec package collision fix.
|
||||||
SharePoint currently exist only on Zenith despite identical intended use.
|
No systems were activated.
|
||||||
- Runtime evidence: earlier theme/greeter, expanded Herdr shortcuts, Handy
|
|
||||||
hold/release/paste, and SharePoint activation checks were incomplete. Old build
|
|
||||||
results do not establish current behavior. Ask in the relevant area.
|
|
||||||
- Handy hang investigation remains parked unless requested: a prior debugger
|
|
||||||
capture found the recorder waiting for an audio chunk before handling stop;
|
|
||||||
Bluetooth failures coincided, and disconnecting Sony WH-1000XM6 helped. The user
|
|
||||||
wants that microphone. Persistent HFP was proposed but never applied or verified;
|
|
||||||
inference-backend changes were not an established fix.
|
|
||||||
- Agent evaluation, new mail ingestion, and company credential isolation were
|
|
||||||
deferred. Secret-management discussion reopens design, not live access.
|
|
||||||
|
|
||||||
The inbox is not a backlog. Detailed old handoffs remain in Git before this batch;
|
Native devenv tools-only startup also passed in an isolated temporary home:
|
||||||
consult them only when their evidence affects a current choice.
|
`/tmp/foundation-native/startup.log`. Company/live/test loading was disabled;
|
||||||
|
SecretSpec 0.20.0 and Python 3.14.7 were available. No company credentials loaded.
|
||||||
|
|
||||||
|
Clean-home manual editor checks passed: direct directory startup renders a Lua-file
|
||||||
|
icon in Oil; opening the note picker after VimEnter reaches TelescopePrompt.
|
||||||
|
Evidence: `/tmp/foundation-editor-check/{startup,notes}.log`. No real notebook or
|
||||||
|
credentials loaded. Built Kanagawa index declares `Inherits=Adwaita,hicolor`.
|
||||||
|
Python source syntax and local documentation links checked; no automated tests added.
|
||||||
|
|
||||||
|
The final review only removed the unaccepted Kubernetes login wrapper and the
|
||||||
|
machine-wide devenv cache setting; the flake-scoped cache remains. Full builds were
|
||||||
|
not repeated for those deletions.
|
||||||
|
|
||||||
|
Builds do not establish interactive acceptance. The user checkpoint remains; do not
|
||||||
|
repeat full builds for documentation-only handoff edits.
|
||||||
|
|
||||||
|
## Review checkpoint
|
||||||
|
|
||||||
|
The final diff was reviewed for correctness, integration and Ponytail complexity.
|
||||||
|
Desktop/capability moves and repository wiring had no material findings. The review
|
||||||
|
removed the speculative Kubernetes login interpreter and kept the devenv cache at
|
||||||
|
flake scope instead of granting it machine-wide trust. The remaining Python has a
|
||||||
|
concrete role: in-memory concurrent secret loading with completeness checks, one-time
|
||||||
|
encrypted credential reshaping, dynamic OBS rclone configuration, or pre-existing
|
||||||
|
dictation/transcription behavior.
|
||||||
|
|
||||||
|
The user checkpoint is still required before this pass is complete. No implementation
|
||||||
|
commit was made in this turn.
|
||||||
|
|
||||||
|
Initial local commit `f164d8b` predates this implementation. Four documentation files
|
||||||
|
were already modified during the design pass; those changes belong to this effort.
|
||||||
|
No remote changes or activation have occurred. External workbench analysis/content
|
||||||
|
changes are unrelated and must not be committed here. Previous external loader
|
||||||
|
copies remain at `/tmp/workbench-environment-before-6k4dwzuo`; only root/workbench environment documentation and ignore entries were updated.
|
||||||
|
Backups: `/tmp/foundation-workbench-docs-bvrs1hu9`. Old external loaders remain
|
||||||
|
until user activation, so the currently running system is not broken. Constellation documents were already
|
||||||
|
superseded and removed in the prior foundation commit.
|
||||||
|
|
||||||
|
Deliberate deferrals remain in design: backups declined, dashboard scrapped,
|
||||||
|
Zenith Plymouth and extra Noctalia keyboard controls deferred, stronger credential
|
||||||
|
isolation/new agent workflows/indexing and unrelated editor redesign out of scope.
|
||||||
+116
-87
@@ -1,107 +1,136 @@
|
|||||||
# Repository design
|
# Repository design
|
||||||
|
|
||||||
These are working decisions, subject to evidence from implementation and use.
|
Working decisions, open to evidence from implementation and use.
|
||||||
|
|
||||||
## Purpose and vocabulary
|
## Model and ownership
|
||||||
|
|
||||||
Build a quiet, keyboard-driven, text-oriented environment from understandable tools
|
Build a quiet, keyboard-driven, text-oriented environment from understandable tools
|
||||||
and standard interfaces. Humans and agents should use the same underlying resources.
|
and standard interfaces. Humans and agents use the same underlying resources.
|
||||||
Use graphical applications where they fit. Consistency should reduce remembering,
|
Graphical applications are deliberate choices where they fit. Streamline existing
|
||||||
without forcing identical bindings or procedures everywhere.
|
workflows rather than requiring a new way of working.
|
||||||
|
|
||||||
- **Host:** machine identity, hardware, and differences in selection.
|
- **Host:** machine identity, hardware and differences in selection.
|
||||||
- **Profile:** a deliberate combination of capabilities.
|
- **Profile:** a deliberate combination of capabilities.
|
||||||
- **Capability:** behavior and necessary integration, potentially spanning NixOS
|
- **Capability:** behavior and necessary integration, potentially spanning several
|
||||||
and Home Manager, multiple applications, or several files.
|
applications, NixOS and Home Manager.
|
||||||
- **Facts:** genuinely shared identity and topology, not a bucket for all settings.
|
- **Facts:** shared identity and topology consumed in multiple places.
|
||||||
- **Theme:** application-specific appearance, including native plugins and assets.
|
- **Theme:** application-specific appearance, including plugins and assets.
|
||||||
Interaction and layout remain with capabilities. Kanagawa is selected; themes
|
Interaction and layout belong to capabilities.
|
||||||
need not fit a palette-only abstraction.
|
|
||||||
|
|
||||||
Retain the composition model. Introduce shared interfaces only for actual consumers.
|
Polaris and Zenith have the same intended daily use. The `work` profile on both is
|
||||||
Capability boundaries matter more than one-module-per-file uniformity.
|
a provisional ownership boundary, not a different workstation variant. Steam and
|
||||||
|
LAN SSH on Polaris, and laptop power/firmware management on Zenith, are deliberate.
|
||||||
|
Orion owns shared services. Tailnet administration supplements existing access;
|
||||||
|
public Orion SSH closes only after private access is verified. Web services stay public.
|
||||||
|
|
||||||
Polaris and Zenith have identical intended use and should offer the same daily
|
Nix owns reproducible installation, integration and selected settings. Applications
|
||||||
experience. Hardware remains host-specific. The workstation
|
own credentials, sessions, content and deliberately interactive preferences. No
|
||||||
profile now imports a provisional `work` profile selecting company network/development
|
plaintext secrets enter Git, Nix evaluation or store outputs. Company credentials
|
||||||
integration, Garden tools, and work Git identity/token integration. Try this boundary
|
use a separate encrypted SOPS document in this private Gitea repository and the
|
||||||
in practice before treating it as settled. Generic editor and development tools
|
existing per-machine age keys. Credential availability is not operational authority.
|
||||||
remain shared. Existing host-only services do not
|
|
||||||
automatically establish a desired difference between machines.
|
|
||||||
|
|
||||||
## Ownership
|
## Coding and composition conventions
|
||||||
|
|
||||||
Nix owns reproducible installation, integration, and deliberately selected settings.
|
Use a flat set of capability owners: `name.nix` when self-contained, otherwise
|
||||||
Applications own credentials, sessions, content, and preferences intentionally left
|
`name/default.nix` with its scripts, assets and operational notes beside it. Put
|
||||||
interactive. Record feature-specific exceptions where they are implemented.
|
manually imported Nix helpers under that owner's `_support/` so import-tree does
|
||||||
|
not discover them. Host hardware helpers remain private to their host.
|
||||||
|
|
||||||
Current layout: company root `~/yookr`, projects in `~/yookr/projects`, workbench in
|
Discovery publishes modules; explicit imports select behavior. Prefer existing
|
||||||
`~/yookr/workbench`; personal projects in `~/projects/{own,ext,forks}`; meeting notes
|
NixOS/Home Manager options and direct module imports. Introduce a shared option or
|
||||||
in `~/sync/notes`. Workspace files remain user-owned. This repository owns the tools-only
|
helper only for actual consumers. Use kebab-case owner/module names that describe
|
||||||
`devShells.x86_64-linux.workbench` environment and shares Garden package definitions
|
purpose. NixOS and Home Manager modules may share the same capability name. Small
|
||||||
with the workstation installation. It follows the same nixpkgs pin as the system.
|
application declarations may remain grouped when they need no substantial integration.
|
||||||
Requests, queries, analysis, findings, private context, runtime data, and the Python
|
Split independent purposes or shared integrations, not every configured package.
|
||||||
project lock remain in the writable workbench. The ordinary workspace `.envrc` files
|
|
||||||
select this environment; credential loading and mounts remain unchanged pending
|
|
||||||
a separate design decision.
|
|
||||||
|
|
||||||
Repositories should hold their code and necessary documentation, not absorb general
|
Keep package definitions with their capability and reuse them across installations
|
||||||
company material. Work is mostly project-based and notes mostly meetings; no new
|
and development environments. Flake inputs belong in `flake.nix` and are locked in
|
||||||
note taxonomy, outer project containers, or company-wide editor search is assumed.
|
`flake.lock`; fixed external sources need a version/revision and hash. Workbench
|
||||||
|
tools follow the system nixpkgs pin. The GitHub devenv CLI retains its upstream
|
||||||
|
build dependencies. Product environment definitions and pins remain product-owned.
|
||||||
|
Use store-qualified executables or `runtimeInputs` in packaged scripts; make runtime
|
||||||
|
paths and failures explicit. Do not duplicate package lists, generated settings or
|
||||||
|
binding references in documentation.
|
||||||
|
|
||||||
## Existing experience and constraints
|
These clarify the agreed model; they are not a one-package-per-file rule, a new
|
||||||
|
testing policy, or a requirement for additional abstractions.
|
||||||
|
|
||||||
These useful decisions and operational cautions are carried forward from earlier
|
## Daily environment
|
||||||
work. They are starting evidence, not fresh runtime verification.
|
|
||||||
|
|
||||||
- Niri workspaces remain flexible. Herdr supplies agent workspace organization;
|
Niri owns navigation and frequent shortcuts; Walker owns application/resource search;
|
||||||
choose agents and arrange panes manually. Preset layouts and launchers were
|
Noctalia owns status and system controls. Workspaces remain flexible and optionally
|
||||||
unwanted. Super belongs to Niri, Ctrl+Alt to direct Herdr actions, and Ctrl
|
named by the user. Terminal titles provide orientation. No project-based workspace
|
||||||
navigation to Neovim; native prefix bindings remain available. Earlier Herdr
|
scheme, heuristic naming or custom Walker project discovery is wanted.
|
||||||
bindings were accepted in use; later additions lack a fresh acceptance report.
|
|
||||||
Configuration and help own the binding reference, rather than a duplicate table.
|
Herdr remains an experiment, not a core dependency. Remove agent-deck, tmux and
|
||||||
- Herdr configuration is Home Manager-owned in `modules/capabilities/ai.nix`.
|
Zellij. Keep Ollama and grounded-docs for experimentation and preserve their data.
|
||||||
After activation reload with Ctrl+Alt+Shift+R (or Ctrl+B then Shift+R). The existing
|
Ollama's embedding model supports grounded-docs. Keep Handy for local dictation and
|
||||||
Home Manager `.bak` mechanism can preserve previous regular files. No fixed agent
|
Orion transcription. Handy preferences, recordings and models remain application-owned.
|
||||||
team or agent-workflow evaluation program is selected.
|
Its push-to-talk release listener requires active-user keyboard access; press from
|
||||||
- Handy provides local plain dictation, mainly English with occasional Dutch.
|
idle, with Super and D on the same keyboard.
|
||||||
Preferences, models, and recordings remain application-owned. Start push-to-talk
|
|
||||||
from idle; D and Super must be on the same keyboard. A short-lived listener handles
|
Both notes entry points open the existing zk note picker with note creation.
|
||||||
releases around Handy's toggle commands. Nix grants active-user keyboard event
|
Notes stay in `~/sync/notes`, mostly meeting material; no new taxonomy. HTTP and
|
||||||
access for this integration. Cloud/LLM cleanup is deferred.
|
database targets remain independently selected and visibly named. Dadbod working
|
||||||
- Native Garden/kubectl/K9s replaced custom workbench inventory helpers. Reusable
|
queries and connection state stay outside Git; see the editor's `database.lua`.
|
||||||
HTTP material is grouped by service and SQL by database. Named targets and editor
|
|
||||||
indicators help orientation but are not access controls. Mail retrieval remains
|
Kanagawa remains the theme with Adwaita fallback icons. rbw unlocks on requested
|
||||||
unresolved; no new ingestion or semantic index was selected.
|
vault access, preserving its lock policy. Outlook PWA owns work email/calendar
|
||||||
- Dadbod working queries persist under `stdpath('data')/db_ui/working`; saving there
|
editing. Mailspring owns personal mail; Thunderbird remains a backup. Noctalia
|
||||||
does not promote work to reusable repository material. Saved-query storage also
|
provides the combined read-only Radicale/Outlook agenda. The user accepts published
|
||||||
contains connection state and must stay out of Git. See
|
ICS link access and supplies the URL privately through runtime settings. Personal
|
||||||
`modules/capabilities/neovim/lua-config/lua/plugins/database.lua`.
|
calendar editing stays on the phone; keep khal/todoman.
|
||||||
- Prior human credential delivery exposes both test/live environments with normal
|
|
||||||
editor startup. Per-connection launchers and per-selection decryption were
|
## Company environment
|
||||||
rejected. Separate read-only agent credentials were desired but unavailable;
|
|
||||||
isolation was deferred. Credential delivery is reopened for discussion, while
|
`~/yookr` is the company root; product repositories are in `~/yookr/projects`.
|
||||||
existing access boundaries remain in force.
|
`~/yookr/workbench` is the access point for company services, databases and files.
|
||||||
- SharePoint sync is currently Zenith-only. Its hourly unit uses two configured
|
This repository owns its environment; requests, queries, analysis, findings, Python
|
||||||
rclone company remotes, private file permissions, and a deletion limit per
|
lock, content and private context stay writable there. The workbench capability
|
||||||
invocation. `X-SwitchMethod = "keep-old"` prevents activation restarting and waiting
|
owns setup and credential/mount instructions.
|
||||||
for an in-flight sync; later timer runs use the updated unit. See
|
|
||||||
`modules/capabilities/sharepoint-reference.nix`. Remote setup, sync completeness,
|
Native devenv replaces direnv, initially with default reload behavior. Migration is
|
||||||
and the full activation fix need confirmation when this area is reviewed.
|
limited to workbench and company-root integration. Product, personal, archived and
|
||||||
|
learning projects are user-migrated; do not retain direnv as a transition.
|
||||||
|
|
||||||
|
Use SecretSpec with existing test-cluster application Secrets and SOPS-backed live
|
||||||
|
credentials. There is no live-cluster access. Company login is explicit. Sources
|
||||||
|
must fail independently, tools remain available, and retries must clear stale values.
|
||||||
|
Normal human editor startup can receive both targets; per-connection decryption and
|
||||||
|
a global environment selector are not wanted. Stronger agent credential isolation
|
||||||
|
is deferred; existing restrictions on company operations remain in force.
|
||||||
|
|
||||||
|
OBS and SharePoint are continuously available as read-only mounts under the workbench
|
||||||
|
on both workstations. User services own lifecycle, independent of shell entry.
|
||||||
|
No persistent content cache or hourly mirror; memory buffers and metadata are accepted.
|
||||||
|
Same-user processes, including agents, can read these mounts. Preserve old local data.
|
||||||
|
|
||||||
## Knowledge and maintenance
|
## Knowledge and maintenance
|
||||||
|
|
||||||
README owns navigation and commands; AGENTS owns repository collaboration rules;
|
README owns navigation and maintenance; AGENTS owns essential durable collaboration
|
||||||
this document owns durable reasoning; current-work owns resumable state. Keep
|
constraints; this document owns rationale/conventions; current-work owns resumable
|
||||||
implementation details near code and use Git instead of chronological handoffs.
|
state. Operational details live beside their owner. Use Git for chronology, replace
|
||||||
Archived plans are historical sources, not authority.
|
superseded state, and remove temporary state when no longer useful.
|
||||||
|
|
||||||
A unified validation command is wanted to prevent repeated agent improvisation.
|
Keep instructions short and authoritative. Add a rule when it prevents a concrete
|
||||||
It must include new and modified working-tree files without changing the Git index,
|
mistake, resolves recurring ambiguity or points to its owner. Prefer formatter and
|
||||||
format, evaluate, and build every host for a full configuration batch. Targeted
|
validation feedback to repeated reminders. This applies the useful principle of
|
||||||
iteration and lightweight documentation checks are accepted. The priority is low
|
progressive disclosure from [OpenAI's harness engineering article](https://openai.com/index/harness-engineering/)
|
||||||
agent token cost, not minimum elapsed time: one invocation, concise results, and
|
without introducing speculative skills, orchestration or evaluation infrastructure.
|
||||||
saved failure logs. Use `just validate` backed by one repository script. Validate a temporary snapshot
|
|
||||||
of tracked and non-ignored new files using working-tree contents; leave the index
|
`just validate` includes working-tree changes and new nonignored files without staging,
|
||||||
untouched. Git ignores remain the file-inclusion boundary. Build
|
formats, evaluates and builds. Concise results and saved logs minimize agent overhead.
|
||||||
success does not establish activation or interactive acceptance.
|
Targeted host builds support iteration; a full run also builds workbench tools.
|
||||||
|
Builds do not prove activation or interactive behavior. Preserve the user's testing
|
||||||
|
policy; this pass does not create a new automated testing policy.
|
||||||
|
|
||||||
|
Keep native update and activation commands. `nix flake update` is normal; selective
|
||||||
|
updates (often `llm-agents`) are appropriate while nixpkgs breakage awaits repair.
|
||||||
|
Activation remains user-owned. No trivial `just` aliases for native commands.
|
||||||
|
|
||||||
|
## Deliberately deferred
|
||||||
|
|
||||||
|
No backups (user declined), Orion dashboard/monitoring (scrapped), new agent
|
||||||
|
workflows/persistence/indexing/isolation, or broader editor redesign without friction.
|
||||||
|
Zenith's Plymouth refresh and extra Noctalia keyboard controls are deferred.
|
||||||
|
The existing single Syncthing `~/sync` layout is retained. TeamViewer is removed.
|
||||||
Generated
+316
-14
@@ -34,6 +34,83 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"cachix": {
|
||||||
|
"inputs": {
|
||||||
|
"devenv": [
|
||||||
|
"devenv"
|
||||||
|
],
|
||||||
|
"flake-compat": [
|
||||||
|
"devenv",
|
||||||
|
"flake-compat"
|
||||||
|
],
|
||||||
|
"git-hooks": [
|
||||||
|
"devenv",
|
||||||
|
"git-hooks"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"devenv",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1788181969,
|
||||||
|
"narHash": "sha256-OUB6hPlFBB9FRdZgZXSye4lDOg+fbrqKe8ePv2IM7NY=",
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "cachix",
|
||||||
|
"rev": "98093e8eea6c1635ef1337a576fa76f3e8bd4f39",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "cachix",
|
||||||
|
"ref": "latest",
|
||||||
|
"repo": "cachix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"crate2nix": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1772186516,
|
||||||
|
"narHash": "sha256-8s28pzmQ6TOIUzznwFibtW1CMieMUl1rYJIxoQYor58=",
|
||||||
|
"owner": "rossng",
|
||||||
|
"repo": "crate2nix",
|
||||||
|
"rev": "ba5dd398e31ee422fbe021767eb83b0650303a6e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "rossng",
|
||||||
|
"repo": "crate2nix",
|
||||||
|
"rev": "ba5dd398e31ee422fbe021767eb83b0650303a6e",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"devenv": {
|
||||||
|
"inputs": {
|
||||||
|
"cachix": "cachix",
|
||||||
|
"crate2nix": "crate2nix",
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
|
"flake-parts": "flake-parts",
|
||||||
|
"ghostty": "ghostty",
|
||||||
|
"git-hooks": "git-hooks",
|
||||||
|
"nix": "nix",
|
||||||
|
"nixd": "nixd",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"rust-overlay": "rust-overlay"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1789773873,
|
||||||
|
"narHash": "sha256-lFR8A3JzpXn4Az9quklprOje/+Njyh9+bP+CE1TCIxI=",
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "devenv",
|
||||||
|
"rev": "2ba2f9ed32596289874c58981a4d3e56cadd639d",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "devenv",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"disko": {
|
"disko": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
@@ -79,7 +156,44 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"flake-compat": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1767039857,
|
||||||
|
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"flake-parts": {
|
"flake-parts": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs-lib": [
|
||||||
|
"devenv",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1788306937,
|
||||||
|
"narHash": "sha256-lbrI1UYVpFgKSsyrU9oeF7FHfnu8nLD9ja0ou9f2rxk=",
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"rev": "f16b25b8c3d2809b87925d0b76652d7821a75c68",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-parts_2": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs-lib": "nixpkgs-lib"
|
"nixpkgs-lib": "nixpkgs-lib"
|
||||||
},
|
},
|
||||||
@@ -97,7 +211,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-parts_2": {
|
"flake-parts_3": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs-lib": [
|
"nixpkgs-lib": [
|
||||||
"llm-agents",
|
"llm-agents",
|
||||||
@@ -118,6 +232,48 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ghostty": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1786026742,
|
||||||
|
"narHash": "sha256-tRtgTg/i3w1nFdRHU2IGekfJN8EyP+HARW4MtoUZyqk=",
|
||||||
|
"owner": "ghostty-org",
|
||||||
|
"repo": "ghostty",
|
||||||
|
"rev": "22d13172cde98a0a4dda05d3d6a3fcb0dd8ed018",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "ghostty-org",
|
||||||
|
"repo": "ghostty",
|
||||||
|
"rev": "22d13172cde98a0a4dda05d3d6a3fcb0dd8ed018",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"git-hooks": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-compat": [
|
||||||
|
"devenv",
|
||||||
|
"flake-compat"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"devenv",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1788267358,
|
||||||
|
"narHash": "sha256-nt+lUqYVpc9Y6JeMd2WmXzCDojasdadKo0mWcluvY2Y=",
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "git-hooks.nix",
|
||||||
|
"rev": "27555e2624241fb116b49095df4caaee85a25691",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "git-hooks.nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"home-manager": {
|
"home-manager": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
@@ -156,10 +312,10 @@
|
|||||||
"llm-agents": {
|
"llm-agents": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"bun2nix": "bun2nix",
|
"bun2nix": "bun2nix",
|
||||||
"flake-parts": "flake-parts_2",
|
"flake-parts": "flake-parts_3",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs_2",
|
||||||
"systems": "systems",
|
"systems": "systems",
|
||||||
"treefmt-nix": "treefmt-nix"
|
"treefmt-nix": "treefmt-nix_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1789804571,
|
"lastModified": 1789804571,
|
||||||
@@ -175,6 +331,46 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nix": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-compat": [
|
||||||
|
"devenv",
|
||||||
|
"flake-compat"
|
||||||
|
],
|
||||||
|
"flake-parts": [
|
||||||
|
"devenv",
|
||||||
|
"flake-parts"
|
||||||
|
],
|
||||||
|
"git-hooks-nix": [
|
||||||
|
"devenv",
|
||||||
|
"git-hooks"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"devenv",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"nixpkgs-23-11": [
|
||||||
|
"devenv"
|
||||||
|
],
|
||||||
|
"nixpkgs-regression": [
|
||||||
|
"devenv"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1788036898,
|
||||||
|
"narHash": "sha256-3NT3yTvoRT7+rxLDNovpyeTDIJkZlBoO72rcu2x9Y9o=",
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "nix",
|
||||||
|
"rev": "b9b81726b38469c55b9706d80d37d6c73cc7f76c",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "cachix",
|
||||||
|
"ref": "devenv-2.35",
|
||||||
|
"repo": "nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nix-index-database": {
|
"nix-index-database": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
@@ -215,6 +411,32 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nixd": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-parts": [
|
||||||
|
"devenv",
|
||||||
|
"flake-parts"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"devenv",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"treefmt-nix": "treefmt-nix"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1788165251,
|
||||||
|
"narHash": "sha256-ITHt6eU6DuwQqlNV1/wehvKYPE6J8sZIlv75CpDjcHI=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixd",
|
||||||
|
"rev": "e2ca72c353cfbc3d63e942fe9aeae4ec497863bf",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixd",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixos-hardware": {
|
"nixos-hardware": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
@@ -237,18 +459,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs-src": "nixpkgs-src"
|
||||||
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1789632929,
|
"lastModified": 1789506231,
|
||||||
"narHash": "sha256-RjR8AyvGlWuw16XRj7C1YDEw4E27ciuyPeB2nDMzgTU=",
|
"narHash": "sha256-vNkJbtmqyBfFhn/HnzQo4ROuoyYWuy/allqTfJb4kMY=",
|
||||||
"owner": "NixOS",
|
"owner": "cachix",
|
||||||
"repo": "nixpkgs",
|
"repo": "devenv-nixpkgs",
|
||||||
"rev": "a32edd7654519351e48e80372a928df336394670",
|
"rev": "c2f38fe7f9e04d9aadd354d380f2bd40531d9737",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "cachix",
|
||||||
"ref": "nixpkgs-unstable",
|
"ref": "rolling",
|
||||||
"repo": "nixpkgs",
|
"repo": "devenv-nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -267,7 +492,40 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nixpkgs-src": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1789370336,
|
||||||
|
"narHash": "sha256-6RSEDHIWQtesQKWSu5qRai8L2h4KgCgMEfJHstW99G4=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "c7def046b9a883d46974757852106483d741586f",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1789632929,
|
||||||
|
"narHash": "sha256-RjR8AyvGlWuw16XRj7C1YDEw4E27ciuyPeB2nDMzgTU=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "a32edd7654519351e48e80372a928df336394670",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_3": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1788834054,
|
"lastModified": 1788834054,
|
||||||
"narHash": "sha256-kkWAS4mE+fmi+u3mxwD9/bfX6DGJ49Tv8O9kzN5r0HQ=",
|
"narHash": "sha256-kkWAS4mE+fmi+u3mxwD9/bfX6DGJ49Tv8O9kzN5r0HQ=",
|
||||||
@@ -302,20 +560,42 @@
|
|||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
|
"devenv": "devenv",
|
||||||
"disko": "disko",
|
"disko": "disko",
|
||||||
"flake-parts": "flake-parts",
|
"flake-parts": "flake-parts_2",
|
||||||
"home-manager": "home-manager",
|
"home-manager": "home-manager",
|
||||||
"import-tree": "import-tree",
|
"import-tree": "import-tree",
|
||||||
"llm-agents": "llm-agents",
|
"llm-agents": "llm-agents",
|
||||||
"nix-index-database": "nix-index-database",
|
"nix-index-database": "nix-index-database",
|
||||||
"nix-wrapper-modules": "nix-wrapper-modules",
|
"nix-wrapper-modules": "nix-wrapper-modules",
|
||||||
"nixos-hardware": "nixos-hardware",
|
"nixos-hardware": "nixos-hardware",
|
||||||
"nixpkgs": "nixpkgs_2",
|
"nixpkgs": "nixpkgs_3",
|
||||||
"noctalia": "noctalia",
|
"noctalia": "noctalia",
|
||||||
"sops-nix": "sops-nix",
|
"sops-nix": "sops-nix",
|
||||||
"walker": "walker"
|
"walker": "walker"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"rust-overlay": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"devenv",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1788332415,
|
||||||
|
"narHash": "sha256-BTFrmyh0oaVDsvA9NNw0YpbbeppTwU0t70iVx672Ew8=",
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"rev": "860d7c835ab91bfc8972b67092f5f2db8e9390a0",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"sops-nix": {
|
"sops-nix": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
@@ -367,6 +647,28 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"treefmt-nix": {
|
"treefmt-nix": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"devenv",
|
||||||
|
"nixd",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1786901030,
|
||||||
|
"narHash": "sha256-WSFCsDSE5ffgD2MqzkM2CYjeFiKhRF/dJUN8uedb6YE=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"rev": "27b3b12a8e6375f28ebe122f07d230ca5459bbfa",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"treefmt-nix_2": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"llm-agents",
|
"llm-agents",
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
{
|
{
|
||||||
description = "NixOS Configuration";
|
description = "NixOS Configuration";
|
||||||
|
|
||||||
|
nixConfig = {
|
||||||
|
extra-substituters = [ "https://devenv.cachix.org" ];
|
||||||
|
extra-trusted-public-keys = [ "devenv.cachix.org-1:w1cLUi8dv3hnoSPGAuibQv+f9TZLr6cv/Hm9XgU50cw=" ];
|
||||||
|
};
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
|
devenv.url = "github:cachix/devenv";
|
||||||
disko = {
|
disko = {
|
||||||
url = "github:nix-community/disko";
|
url = "github:nix-community/disko";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
|||||||
File renamed without changes.
@@ -0,0 +1,14 @@
|
|||||||
|
# AI tools
|
||||||
|
|
||||||
|
Nix installs the tools, assets, skills and system Codex defaults. Codex owns its
|
||||||
|
writable user configuration; credentials, session history and other runtime state
|
||||||
|
remain outside this repository. `instructions/codex.md` owns global agent guidance.
|
||||||
|
|
||||||
|
Herdr is optional experimentation. Reload its managed configuration with
|
||||||
|
Ctrl+Alt+Shift+R (or Ctrl+B then Shift+R); its configuration owns the binding reference.
|
||||||
|
Home Manager may preserve an earlier regular configuration file with `.bak`.
|
||||||
|
|
||||||
|
Ollama supplies `nomic-embed-text` for grounded-docs. The latter runs on localhost
|
||||||
|
port 6280 with persistent Podman volumes. Removing another tool must not delete
|
||||||
|
these models or volumes. No mandatory agent persistence or orchestration workflow
|
||||||
|
is defined here.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{ pkgs }:
|
{ pkgs }:
|
||||||
let
|
let
|
||||||
sources = import ./_sources.nix { inherit pkgs; };
|
sources = import ./sources.nix { inherit pkgs; };
|
||||||
context7Headers = pkgs.writeShellScript "context7-http-headers" ''
|
context7Headers = pkgs.writeShellScript "context7-http-headers" ''
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
CONTEXT7_KEY_FILE="''${XDG_CONFIG_HOME:-$HOME/.config}/context7/api-key"
|
CONTEXT7_KEY_FILE="''${XDG_CONFIG_HOME:-$HOME/.config}/context7/api-key"
|
||||||
@@ -26,7 +26,6 @@ in
|
|||||||
inherit context7Headers codexHooks;
|
inherit context7Headers codexHooks;
|
||||||
skills = {
|
skills = {
|
||||||
context7-mcp = ../skills/context7-mcp;
|
context7-mcp = ../skills/context7-mcp;
|
||||||
# nixos-maintainer = ../skills/nixos-maintainer;
|
|
||||||
herdr = "${sources.herdr}/skills/herdr";
|
herdr = "${sources.herdr}/skills/herdr";
|
||||||
};
|
};
|
||||||
servers = {
|
servers = {
|
||||||
File renamed without changes.
@@ -7,7 +7,7 @@ in
|
|||||||
flake.modules.nixos.ai =
|
flake.modules.nixos.ai =
|
||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
let
|
let
|
||||||
ai = import ./ai/_assets.nix { inherit pkgs; };
|
ai = import ./_support/assets.nix { inherit pkgs; };
|
||||||
codexConfig = (pkgs.formats.toml { }).generate "codex-config.toml" {
|
codexConfig = (pkgs.formats.toml { }).generate "codex-config.toml" {
|
||||||
model = "gpt-5.6-sol";
|
model = "gpt-5.6-sol";
|
||||||
model_reasoning_effort = "high";
|
model_reasoning_effort = "high";
|
||||||
@@ -15,11 +15,6 @@ in
|
|||||||
service_tier = "default";
|
service_tier = "default";
|
||||||
approvals_reviewer = "auto_review";
|
approvals_reviewer = "auto_review";
|
||||||
features.hooks = true;
|
features.hooks = true;
|
||||||
notify = [
|
|
||||||
"${pkgs.llm-agents.agent-deck}/bin/agent-deck"
|
|
||||||
"codex-notify"
|
|
||||||
];
|
|
||||||
|
|
||||||
tui = {
|
tui = {
|
||||||
status_line = [
|
status_line = [
|
||||||
"model-with-reasoning"
|
"model-with-reasoning"
|
||||||
@@ -71,7 +66,7 @@ in
|
|||||||
flake.modules.homeManager.ai =
|
flake.modules.homeManager.ai =
|
||||||
{ pkgs, lib, ... }:
|
{ pkgs, lib, ... }:
|
||||||
let
|
let
|
||||||
ai = import ./ai/_assets.nix { inherit pkgs; };
|
ai = import ./_support/assets.nix { inherit pkgs; };
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
services.podman = {
|
services.podman = {
|
||||||
@@ -105,9 +100,7 @@ in
|
|||||||
inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.codex
|
inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.codex
|
||||||
pkgs.llm-agents.pi
|
pkgs.llm-agents.pi
|
||||||
pkgs.llm-agents.claude-code
|
pkgs.llm-agents.claude-code
|
||||||
pkgs.llm-agents.agent-deck
|
|
||||||
pkgs.llm-agents.herdr
|
pkgs.llm-agents.herdr
|
||||||
pkgs.tmux
|
|
||||||
pkgs.ctx7
|
pkgs.ctx7
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -190,7 +183,7 @@ in
|
|||||||
name: source: lib.nameValuePair ".agents/skills/${name}" { inherit source; }
|
name: source: lib.nameValuePair ".agents/skills/${name}" { inherit source; }
|
||||||
) ai.skills
|
) ai.skills
|
||||||
// {
|
// {
|
||||||
".codex/AGENTS.md".text = builtins.readFile ./ai/instructions/codex.md;
|
".codex/AGENTS.md".text = builtins.readFile ./instructions/codex.md;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
File renamed without changes.
File renamed without changes.
@@ -35,16 +35,6 @@
|
|||||||
xdg.mimeApps.defaultApplicationPackages = [ pkgs.vivaldi ];
|
xdg.mimeApps.defaultApplicationPackages = [ pkgs.vivaldi ];
|
||||||
};
|
};
|
||||||
|
|
||||||
flake.modules.homeManager.nautilus =
|
|
||||||
{ config, pkgs, ... }:
|
|
||||||
{
|
|
||||||
home.packages = [ pkgs.nautilus ];
|
|
||||||
gtk.gtk3.bookmarks = [
|
|
||||||
"sftp://${config.facts.topology.server.sshAlias} Orion VPS"
|
|
||||||
];
|
|
||||||
xdg.mimeApps.defaultApplicationPackages = [ pkgs.nautilus ];
|
|
||||||
};
|
|
||||||
|
|
||||||
flake.modules.homeManager.imv =
|
flake.modules.homeManager.imv =
|
||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
@@ -75,7 +65,6 @@
|
|||||||
dbeaver-bin
|
dbeaver-bin
|
||||||
onlyoffice-desktopeditors
|
onlyoffice-desktopeditors
|
||||||
pinta
|
pinta
|
||||||
zellij
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
|
{ inputs, ... }:
|
||||||
{
|
{
|
||||||
|
perSystem = { pkgs, ... }: {
|
||||||
|
packages.devenv = inputs.devenv.packages.${pkgs.stdenv.hostPlatform.system}.devenv;
|
||||||
|
};
|
||||||
flake.modules.homeManager.dev-tools =
|
flake.modules.homeManager.dev-tools =
|
||||||
{ config, pkgs, ... }:
|
{ config, pkgs, ... }:
|
||||||
{
|
{
|
||||||
home.sessionVariables.CARGO_HOME = "${config.xdg.dataHome}/cargo";
|
home.sessionVariables.CARGO_HOME = "${config.xdg.dataHome}/cargo";
|
||||||
home.packages = with pkgs; [
|
home.packages = with pkgs; [
|
||||||
|
inputs.devenv.packages.${pkgs.stdenv.hostPlatform.system}.devenv
|
||||||
bruno
|
bruno
|
||||||
kubectl
|
kubectl
|
||||||
kubelogin-oidc
|
kubelogin-oidc
|
||||||
@@ -20,14 +25,8 @@
|
|||||||
programs.ripgrep.enable = true;
|
programs.ripgrep.enable = true;
|
||||||
programs.k9s.enable = true;
|
programs.k9s.enable = true;
|
||||||
|
|
||||||
programs.direnv = {
|
programs.zsh.initContent = ''
|
||||||
enable = true;
|
eval "$(devenv hook zsh)"
|
||||||
nix-direnv.enable = true;
|
'';
|
||||||
|
|
||||||
config.global = {
|
|
||||||
hide_env_diff = true;
|
|
||||||
log_format = "↳ %s";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
flake.modules.nixos.file-management = {
|
||||||
|
services.gvfs.enable = true;
|
||||||
|
services.udisks2.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
flake.modules.homeManager.file-management =
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
{
|
||||||
|
home.packages = [ pkgs.nautilus ];
|
||||||
|
gtk.gtk3.bookmarks = [
|
||||||
|
"sftp://${config.facts.topology.server.sshAlias} Orion VPS"
|
||||||
|
];
|
||||||
|
xdg.mimeApps.defaultApplicationPackages = [ pkgs.nautilus ];
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
File renamed without changes.
@@ -34,7 +34,7 @@
|
|||||||
Requisite = [ "handy.service" ];
|
Requisite = [ "handy.service" ];
|
||||||
After = [ "handy.service" ];
|
After = [ "handy.service" ];
|
||||||
};
|
};
|
||||||
Service.ExecStart = "${python}/bin/python ${./handy/_push_to_talk.py} ${pkgs.handy}/bin/handy";
|
Service.ExecStart = "${python}/bin/python ${./push_to_talk.py} ${pkgs.handy}/bin/handy";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
File renamed without changes.
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
from unittest.mock import Mock, patch
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
import _push_to_talk as ptt
|
import push_to_talk as ptt
|
||||||
|
|
||||||
down = [ptt.key.KEY_LEFTMETA, ptt.key.KEY_D]
|
down = [ptt.key.KEY_LEFTMETA, ptt.key.KEY_D]
|
||||||
|
|
||||||
File renamed without changes.
@@ -13,7 +13,7 @@ in
|
|||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
nvimTreesitter = pkgs.vimPlugins.nvim-treesitter;
|
nvimTreesitter = pkgs.vimPlugins.nvim-treesitter;
|
||||||
svelteLanguageServer = import ../_svelte-language-server.nix { inherit pkgs; };
|
svelteLanguageServer = import ./_support/svelte-language-server.nix { inherit pkgs; };
|
||||||
svelteGrammar = nvimTreesitter.builtGrammars.svelte.overrideAttrs (_: {
|
svelteGrammar = nvimTreesitter.builtGrammars.svelte.overrideAttrs (_: {
|
||||||
version = "0.0.0+rev=c2457b9";
|
version = "0.0.0+rev=c2457b9";
|
||||||
src = pkgs.fetchFromGitHub {
|
src = pkgs.fetchFromGitHub {
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
require("lz.n").load({
|
require("lz.n").load({
|
||||||
{
|
{
|
||||||
"mini.nvim",
|
"mini.nvim",
|
||||||
event = "VimEnter",
|
-- Icons must exist before Oil opens an initial directory buffer.
|
||||||
|
lazy = false,
|
||||||
after = function()
|
after = function()
|
||||||
require("mini.ai").setup({ n_lines = 500 })
|
require("mini.ai").setup({ n_lines = 500 })
|
||||||
require("mini.surround").setup()
|
require("mini.surround").setup()
|
||||||
|
|||||||
+6
-2
@@ -25,9 +25,13 @@ in
|
|||||||
spawn = browser;
|
spawn = browser;
|
||||||
_props.hotkey-overlay-title = "Browser";
|
_props.hotkey-overlay-title = "Browser";
|
||||||
};
|
};
|
||||||
|
"Mod+Shift+N" = {
|
||||||
|
spawn-sh = "rename-workspace";
|
||||||
|
_props.hotkey-overlay-title = "Name workspace (empty clears)";
|
||||||
|
};
|
||||||
"Mod+N" = {
|
"Mod+N" = {
|
||||||
spawn-sh = "open-daily-note";
|
spawn-sh = "open-notes";
|
||||||
_props.hotkey-overlay-title = "Daily Note";
|
_props.hotkey-overlay-title = "Find or create notes";
|
||||||
};
|
};
|
||||||
"Mod+Space" = {
|
"Mod+Space" = {
|
||||||
_props.repeat = false;
|
_props.repeat = false;
|
||||||
File renamed without changes.
@@ -13,10 +13,6 @@ in
|
|||||||
|
|
||||||
programs.niri.enable = true;
|
programs.niri.enable = true;
|
||||||
|
|
||||||
services = {
|
|
||||||
gvfs.enable = true;
|
|
||||||
udisks2.enable = true;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
flake.modules.homeManager.niri =
|
flake.modules.homeManager.niri =
|
||||||
@@ -27,7 +23,22 @@ in
|
|||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
swapMonitorWorkspaces = import ./_shortcuts.nix { inherit pkgs; };
|
swapMonitorWorkspaces = import ./_support/shortcuts.nix { inherit pkgs; };
|
||||||
|
renameWorkspace = pkgs.writeShellApplication {
|
||||||
|
name = "rename-workspace";
|
||||||
|
runtimeInputs = [
|
||||||
|
pkgs.niri
|
||||||
|
pkgs.zenity
|
||||||
|
];
|
||||||
|
text = ''
|
||||||
|
name=$(zenity --entry --title="Workspace name" --text="Name this workspace (empty clears its name):") || exit 0
|
||||||
|
if [[ -n "$name" ]]; then
|
||||||
|
niri msg action set-workspace-name "$name"
|
||||||
|
else
|
||||||
|
niri msg action unset-workspace-name
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
machine = config.facts.machine;
|
machine = config.facts.machine;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
@@ -41,7 +52,10 @@ in
|
|||||||
wireplumber
|
wireplumber
|
||||||
wtype
|
wtype
|
||||||
]
|
]
|
||||||
++ [ swapMonitorWorkspaces ];
|
++ [
|
||||||
|
swapMonitorWorkspaces
|
||||||
|
renameWorkspace
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
wayland.windowManager.niri = {
|
wayland.windowManager.niri = {
|
||||||
@@ -121,7 +135,7 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
binds = import ./_bindings.nix {
|
binds = import ./_support/bindings.nix {
|
||||||
inherit (config.desktop.commands)
|
inherit (config.desktop.commands)
|
||||||
browser
|
browser
|
||||||
launcher
|
launcher
|
||||||
|
|||||||
@@ -124,7 +124,11 @@
|
|||||||
volume.show_label = false;
|
volume.show_label = false;
|
||||||
network.show_label = false;
|
network.show_label = false;
|
||||||
battery.show_label = false;
|
battery.show_label = false;
|
||||||
workspaces.show_labels = false;
|
workspaces = {
|
||||||
|
show_labels = true;
|
||||||
|
label_source = "name";
|
||||||
|
max_label_chars = 16;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -38,25 +38,25 @@ in
|
|||||||
|
|
||||||
# {{title}}
|
# {{title}}
|
||||||
'';
|
'';
|
||||||
openDailyNote = pkgs.writeShellApplication {
|
openNotes = pkgs.writeShellApplication {
|
||||||
name = "open-daily-note";
|
name = "open-notes";
|
||||||
text = ''
|
text = ''
|
||||||
exec ${lib.getExe config.programs.kitty.package} --detach \
|
exec ${lib.getExe config.programs.kitty.package} --detach \
|
||||||
--directory "${home}/sync/notes" \
|
--directory "${home}/sync/notes" \
|
||||||
${lib.getExe pkgs.zsh} -lic 'zk daily'
|
nvim '+autocmd VimEnter * ++once ZkNotes'
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
home.packages = [
|
home.packages = [
|
||||||
openDailyNote
|
openNotes
|
||||||
(pkgs.makeDesktopItem {
|
(pkgs.makeDesktopItem {
|
||||||
name = "notes";
|
name = "notes";
|
||||||
desktopName = "Notes";
|
desktopName = "Notes";
|
||||||
icon = "text-editor";
|
icon = "text-editor";
|
||||||
exec = "nvim .";
|
exec = lib.getExe openNotes;
|
||||||
path = "${home}/sync/notes";
|
path = "${home}/sync/notes";
|
||||||
terminal = true;
|
terminal = false;
|
||||||
})
|
})
|
||||||
pkgs.ripgrep-all
|
pkgs.ripgrep-all
|
||||||
pkgs.zk
|
pkgs.zk
|
||||||
|
|||||||
File renamed without changes.
File renamed without changes.
@@ -1,49 +0,0 @@
|
|||||||
{ config, ... }:
|
|
||||||
{
|
|
||||||
flake.modules.homeManager.sharepoint-reference =
|
|
||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
rcloneConfig = "${config.xdg.configHome}/rclone/rclone.conf";
|
|
||||||
destination = "${config.xdg.dataHome}/yookr-reference/sharepoint";
|
|
||||||
in
|
|
||||||
{
|
|
||||||
systemd.user.services.sharepoint-reference-sync = {
|
|
||||||
Unit = {
|
|
||||||
Description = "Refresh the local SharePoint reference mirror";
|
|
||||||
ConditionPathExists = rcloneConfig;
|
|
||||||
# Let an in-flight sync finish; activation must not restart and wait for it.
|
|
||||||
X-SwitchMethod = "keep-old";
|
|
||||||
};
|
|
||||||
|
|
||||||
Service = {
|
|
||||||
Type = "oneshot";
|
|
||||||
UMask = "0077";
|
|
||||||
ExecStart = [
|
|
||||||
"${lib.getExe pkgs.rclone} --config ${rcloneConfig} sync company-sharepoint: ${destination}/Algemeen --max-delete 100"
|
|
||||||
"${lib.getExe pkgs.rclone} --config ${rcloneConfig} sync company-sharepoint-projecten: ${destination}/Projecten --max-delete 100"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.user.timers.sharepoint-reference-sync = {
|
|
||||||
Unit.Description = "Refresh the local SharePoint reference mirror hourly";
|
|
||||||
|
|
||||||
Timer = {
|
|
||||||
OnCalendar = "hourly";
|
|
||||||
Persistent = true;
|
|
||||||
RandomizedDelaySec = "10m";
|
|
||||||
};
|
|
||||||
|
|
||||||
Install.WantedBy = [ "timers.target" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
flake.modules.nixos.sharepoint-reference = {
|
|
||||||
home-manager.sharedModules = [ config.flake.modules.homeManager.sharepoint-reference ];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -52,7 +52,18 @@
|
|||||||
history.path = "${config.xdg.dataHome}/zsh_history";
|
history.path = "${config.xdg.dataHome}/zsh_history";
|
||||||
|
|
||||||
initContent = ''
|
initContent = ''
|
||||||
source <(gardenctl rc zsh --no-completion)
|
# Terminal/window switchers show the working directory and active command.
|
||||||
|
autoload -Uz add-zsh-hook
|
||||||
|
function terminal-title-precmd() {
|
||||||
|
print -Pn '\e]2;%m: %~\a'
|
||||||
|
}
|
||||||
|
function terminal-title-preexec() {
|
||||||
|
local command="''${1//[[:cntrl:]]/}"
|
||||||
|
print -Pn '\e]2;%m: %~ — '
|
||||||
|
print -rn -- "$command"$'\a'
|
||||||
|
}
|
||||||
|
add-zsh-hook precmd terminal-title-precmd
|
||||||
|
add-zsh-hook preexec terminal-title-preexec
|
||||||
|
|
||||||
bindkey -v
|
bindkey -v
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
---
|
|
||||||
name: nixos-maintainer
|
|
||||||
description: Maintain this NixOS and Home Manager flake by inspecting, changing, simplifying, or validating its configuration. Use for system configuration work in the NixOS repository, not generic Nix questions or unrelated projects.
|
|
||||||
---
|
|
||||||
|
|
||||||
# NixOS Maintainer
|
|
||||||
|
|
||||||
Read the applicable `AGENTS.md` and the complete current owner of the behavior
|
|
||||||
before editing. Trace its imports through the host, profile, and capability
|
|
||||||
modules so the change lands at the narrowest shared level that matches its real
|
|
||||||
scope.
|
|
||||||
|
|
||||||
Prefer an existing module or native NixOS/Home Manager option. Keep mutable,
|
|
||||||
secret, credential, and application-owned state outside the Nix store. Verify
|
|
||||||
unfamiliar pinned interfaces against the exact package source or current primary
|
|
||||||
documentation.
|
|
||||||
|
|
||||||
Preserve unrelated work. Format touched Nix files and use the narrowest useful
|
|
||||||
evaluation for configuration changes. Build affected hosts only when needed to
|
|
||||||
resolve a concrete concern or explicitly requested; instruction-only edits do
|
|
||||||
not need system builds. Do not add tests or migration/compatibility code by
|
|
||||||
default. Explain manual steps for breaking changes.
|
|
||||||
|
|
||||||
Do not switch or boot a generation unless the user explicitly requests activation.
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
flake.modules.nixos.tailscale = {
|
||||||
|
services.tailscale.enable = true;
|
||||||
|
# Keep existing SSH exposure until tailnet enrollment and access are verified.
|
||||||
|
networking.firewall.interfaces.tailscale0.allowedTCPPorts = [ 22 ];
|
||||||
|
};
|
||||||
|
}
|
||||||
File renamed without changes.
+11
-5
@@ -1,6 +1,6 @@
|
|||||||
{ config, lib, ... }:
|
{ config, lib, ... }:
|
||||||
let
|
let
|
||||||
palette = (import ./_kanagawa-palette.nix).palette;
|
palette = (import ./palette.nix).palette;
|
||||||
hex = lib.removePrefix "#";
|
hex = lib.removePrefix "#";
|
||||||
wallpaper = ./assets/green-leaves.png;
|
wallpaper = ./assets/green-leaves.png;
|
||||||
cursor = {
|
cursor = {
|
||||||
@@ -64,8 +64,12 @@ in
|
|||||||
gtk4.theme = null;
|
gtk4.theme = null;
|
||||||
iconTheme = {
|
iconTheme = {
|
||||||
name = "Kanagawa";
|
name = "Kanagawa";
|
||||||
package = pkgs.kanagawa-icon-theme.overrideAttrs (_: {
|
package = pkgs.kanagawa-icon-theme.overrideAttrs (old: {
|
||||||
inherit src version;
|
inherit src version;
|
||||||
|
postInstall = (old.postInstall or "") + ''
|
||||||
|
find "$out/share/icons" -name index.theme -exec \
|
||||||
|
sed -i 's/^Inherits=.*/Inherits=Adwaita,hicolor/' {} +
|
||||||
|
'';
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -75,6 +79,8 @@ in
|
|||||||
platformTheme.name = "gtk3";
|
platformTheme.name = "gtk3";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
home.packages = [ pkgs.adwaita-icon-theme ];
|
||||||
|
|
||||||
xdg.systemDirs.data = [
|
xdg.systemDirs.data = [
|
||||||
"${pkgs.gsettings-desktop-schemas}/share/gsettings-schemas/${pkgs.gsettings-desktop-schemas.name}"
|
"${pkgs.gsettings-desktop-schemas}/share/gsettings-schemas/${pkgs.gsettings-desktop-schemas.name}"
|
||||||
"${pkgs.gtk3}/share/gsettings-schemas/${pkgs.gtk3.name}"
|
"${pkgs.gtk3}/share/gsettings-schemas/${pkgs.gtk3.name}"
|
||||||
@@ -90,7 +96,7 @@ in
|
|||||||
{
|
{
|
||||||
boot.loader.limine.style = {
|
boot.loader.limine.style = {
|
||||||
wallpapers = [ pkgs.nixos-artwork.wallpapers.simple-dark-gray-bootloader.gnomeFilePath ];
|
wallpapers = [ pkgs.nixos-artwork.wallpapers.simple-dark-gray-bootloader.gnomeFilePath ];
|
||||||
wallpaperStyle = "stretched";
|
wallpaperStyle = "centered";
|
||||||
backdrop = hex palette.secondaryBackground;
|
backdrop = hex palette.secondaryBackground;
|
||||||
|
|
||||||
graphicalTerminal = {
|
graphicalTerminal = {
|
||||||
@@ -128,7 +134,7 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
interface = {
|
interface = {
|
||||||
branding = config.networking.hostName;
|
branding = "NixOS - ${config.networking.hostName}";
|
||||||
brandingColor = hex palette.accents.blue;
|
brandingColor = hex palette.accents.blue;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -297,7 +303,7 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
flake.modules.homeManager.walker = {
|
flake.modules.homeManager.walker = {
|
||||||
programs.walker.themes.constellation.style = lib.mkAfter ''
|
programs.walker.themes.desktop.style = lib.mkAfter ''
|
||||||
@define-color window_bg_color ${palette.background};
|
@define-color window_bg_color ${palette.background};
|
||||||
@define-color accent_bg_color ${palette.selectionBackground};
|
@define-color accent_bg_color ${palette.selectionBackground};
|
||||||
@define-color theme_fg_color ${palette.foreground};
|
@define-color theme_fg_color ${palette.foreground};
|
||||||
File renamed without changes.
@@ -1,2 +1,2 @@
|
|||||||
# Select a complete theme module: plugins, assets and behavior as well as colors.
|
# Select a complete theme module: plugins, assets and behavior as well as colors.
|
||||||
{ imports = [ ./_themes/kanagawa.nix ]; }
|
{ imports = [ ./_support/kanagawa.nix ]; }
|
||||||
+2
-2
@@ -31,7 +31,7 @@
|
|||||||
executable = true;
|
executable = true;
|
||||||
text = ''
|
text = ''
|
||||||
#!${diarizationPython}/bin/python3
|
#!${diarizationPython}/bin/python3
|
||||||
${builtins.readFile ./_diarize-transcript.py}
|
${builtins.readFile ./diarize-transcript.py}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
whisper = pkgs.whisper-cpp;
|
whisper = pkgs.whisper-cpp;
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
findutils
|
findutils
|
||||||
whisper
|
whisper
|
||||||
];
|
];
|
||||||
text = builtins.readFile ./_transcribe-recordings.sh;
|
text = builtins.readFile ./transcribe-recordings.sh;
|
||||||
};
|
};
|
||||||
home = config.home.homeDirectory;
|
home = config.home.homeDirectory;
|
||||||
in
|
in
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -1,171 +0,0 @@
|
|||||||
{ config, inputs, ... }:
|
|
||||||
{
|
|
||||||
flake.modules.nixos.walker = {
|
|
||||||
home-manager.sharedModules = [ config.flake.modules.homeManager.walker ];
|
|
||||||
|
|
||||||
nix.settings = {
|
|
||||||
extra-substituters = [
|
|
||||||
"https://walker.cachix.org"
|
|
||||||
"https://walker-git.cachix.org"
|
|
||||||
];
|
|
||||||
extra-trusted-public-keys = [
|
|
||||||
"walker.cachix.org-1:fG8q+uAaMqhsMxWjwvk0IMb4mFPFLqHjuvfwQxE4oJM="
|
|
||||||
"walker-git.cachix.org-1:vmC0ocfPWh0S/vRAQGtChuiZBTAe4wiKDeyyXM0/7pM="
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
flake.modules.homeManager.walker =
|
|
||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
homeDir = config.home.homeDirectory;
|
|
||||||
projectRoots = [
|
|
||||||
{
|
|
||||||
scope = "work";
|
|
||||||
path = "${homeDir}/yookr/projects";
|
|
||||||
}
|
|
||||||
]
|
|
||||||
++
|
|
||||||
map
|
|
||||||
(scope: {
|
|
||||||
inherit scope;
|
|
||||||
path = "${config.xdg.userDirs.projects}/${scope}";
|
|
||||||
})
|
|
||||||
[
|
|
||||||
"own"
|
|
||||||
"ext"
|
|
||||||
"forks"
|
|
||||||
];
|
|
||||||
walkerDefaults = builtins.fromTOML (builtins.readFile "${inputs.walker}/resources/config.toml");
|
|
||||||
|
|
||||||
launcher = pkgs.writeShellApplication {
|
|
||||||
name = "walker-launcher";
|
|
||||||
runtimeInputs = [ pkgs.libressl.nc ];
|
|
||||||
text = ''
|
|
||||||
exec nc -U "$XDG_RUNTIME_DIR/walker/walker.sock"
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
openProject = pkgs.writeShellApplication {
|
|
||||||
name = "open-project";
|
|
||||||
text = ''
|
|
||||||
project_path="''${1:-}"
|
|
||||||
if [[ -z "$project_path" ]]; then
|
|
||||||
IFS= read -r project_path || [[ -n "$project_path" ]]
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec ${lib.getExe config.xdg.terminal-exec.package} --dir="$project_path" \
|
|
||||||
${lib.getExe pkgs.zsh} -lic 'nvim .; exec zsh -l'
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
imports = [ inputs.walker.homeManagerModules.default ];
|
|
||||||
|
|
||||||
desktop.commands.launcher = [ (lib.getExe launcher) ];
|
|
||||||
home.packages = [ openProject ];
|
|
||||||
|
|
||||||
xdg.configFile."elephant/menus/projects.lua".text = ''
|
|
||||||
Name = "projects"
|
|
||||||
NamePretty = "Projects"
|
|
||||||
Description = "Projects and workspaces"
|
|
||||||
Icon = "folder"
|
|
||||||
Action = "${lib.getExe openProject}"
|
|
||||||
SearchName = true
|
|
||||||
RefreshOnChange = {
|
|
||||||
${lib.concatMapStringsSep "\n " (root: ''"${root.path}",'') projectRoots}
|
|
||||||
}
|
|
||||||
|
|
||||||
local roots = {
|
|
||||||
${lib.concatMapStringsSep "\n " (
|
|
||||||
root: ''{ scope = "${root.scope}", path = "${root.path}" },''
|
|
||||||
) projectRoots}
|
|
||||||
}
|
|
||||||
|
|
||||||
local function repositories(root)
|
|
||||||
return io.popen(
|
|
||||||
"${lib.getExe pkgs.findutils} " .. root ..
|
|
||||||
" -mindepth 1 \\( -type d \\( -name .archive -o -name .worktrees \\) -prune \\)" ..
|
|
||||||
" -o \\( -name .git -print \\) 2>/dev/null"
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
function GetEntries()
|
|
||||||
local entries = {
|
|
||||||
{
|
|
||||||
Text = "Yookr",
|
|
||||||
Subtext = "Company workspace",
|
|
||||||
Value = "${homeDir}/yookr",
|
|
||||||
Keywords = { "work", "company", "workbench" },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, root in ipairs(roots) do
|
|
||||||
local handle = repositories(root.path)
|
|
||||||
if handle then
|
|
||||||
for git_path in handle:lines() do
|
|
||||||
local project = git_path:gsub("/%.git$", "")
|
|
||||||
local relative = project:sub(#root.path + 2)
|
|
||||||
table.insert(entries, {
|
|
||||||
Text = project:match("([^/]+)$"),
|
|
||||||
Subtext = root.scope .. " · " .. relative,
|
|
||||||
Value = project,
|
|
||||||
Keywords = { root.scope, relative, project },
|
|
||||||
})
|
|
||||||
end
|
|
||||||
handle:close()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return entries
|
|
||||||
end
|
|
||||||
'';
|
|
||||||
|
|
||||||
programs.walker = {
|
|
||||||
enable = true;
|
|
||||||
runAsService = true;
|
|
||||||
|
|
||||||
config.theme = "constellation";
|
|
||||||
themes.constellation = {
|
|
||||||
layouts.layout =
|
|
||||||
lib.replaceStrings
|
|
||||||
[ ''<property name="height-request">570</property>'' ]
|
|
||||||
[ ''<property name="height-request">460</property>'' ]
|
|
||||||
(builtins.readFile "${inputs.walker}/resources/themes/default/layout.xml");
|
|
||||||
style = lib.mkBefore (
|
|
||||||
builtins.readFile "${inputs.walker}/resources/themes/default/style.css"
|
|
||||||
+ ''
|
|
||||||
.box-wrapper {
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 10px;
|
|
||||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
|
|
||||||
}
|
|
||||||
.search-container, .item-box, .preview { border-radius: 6px; }
|
|
||||||
.input { padding: 8px 10px; }
|
|
||||||
.item-box { padding: 5px 8px; }
|
|
||||||
.large-icons { -gtk-icon-size: 24px; }
|
|
||||||
.item-image-text { font-size: 24px; }
|
|
||||||
.item-subtext { opacity: 0.75; }
|
|
||||||
.item-quick-activation { padding: 3px 5px; }
|
|
||||||
.keybinds { padding-top: 6px; }
|
|
||||||
.keybind-bind { opacity: 0.65; }
|
|
||||||
''
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
config.providers = {
|
|
||||||
default = walkerDefaults.providers.default ++ [ "menus:projects" ];
|
|
||||||
prefixes = walkerDefaults.providers.prefixes ++ [
|
|
||||||
{
|
|
||||||
provider = "bitwarden";
|
|
||||||
prefix = "?";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
{ config, inputs, ... }:
|
||||||
|
{
|
||||||
|
flake.modules.nixos.walker = {
|
||||||
|
home-manager.sharedModules = [ config.flake.modules.homeManager.walker ];
|
||||||
|
|
||||||
|
nix.settings = {
|
||||||
|
extra-substituters = [
|
||||||
|
"https://walker.cachix.org"
|
||||||
|
"https://walker-git.cachix.org"
|
||||||
|
];
|
||||||
|
extra-trusted-public-keys = [
|
||||||
|
"walker.cachix.org-1:fG8q+uAaMqhsMxWjwvk0IMb4mFPFLqHjuvfwQxE4oJM="
|
||||||
|
"walker-git.cachix.org-1:vmC0ocfPWh0S/vRAQGtChuiZBTAe4wiKDeyyXM0/7pM="
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
flake.modules.homeManager.walker =
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
elephantPackages = inputs.walker.inputs.elephant.packages.${pkgs.stdenv.hostPlatform.system};
|
||||||
|
# Upstream initializes rbw at startup. Drop this patch when it supports lazy vault access.
|
||||||
|
providers = elephantPackages.elephant-providers.overrideAttrs (old: {
|
||||||
|
patches = (old.patches or [ ]) ++ [ ./demand-driven-vault.patch ];
|
||||||
|
});
|
||||||
|
elephant = elephantPackages.elephant-with-providers.overrideAttrs (old: {
|
||||||
|
installPhase =
|
||||||
|
builtins.replaceStrings [ "${elephantPackages.elephant-providers}" ] [ "${providers}" ]
|
||||||
|
old.installPhase;
|
||||||
|
});
|
||||||
|
walkerDefaults = builtins.fromTOML (builtins.readFile "${inputs.walker}/resources/config.toml");
|
||||||
|
|
||||||
|
launcher = pkgs.writeShellApplication {
|
||||||
|
name = "walker-launcher";
|
||||||
|
runtimeInputs = [ pkgs.libressl.nc ];
|
||||||
|
text = ''
|
||||||
|
exec nc -U "$XDG_RUNTIME_DIR/walker/walker.sock"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [ inputs.walker.homeManagerModules.default ];
|
||||||
|
|
||||||
|
programs.elephant.package = elephant;
|
||||||
|
|
||||||
|
desktop.commands.launcher = [ (lib.getExe launcher) ];
|
||||||
|
programs.walker = {
|
||||||
|
enable = true;
|
||||||
|
runAsService = true;
|
||||||
|
|
||||||
|
config.theme = "desktop";
|
||||||
|
themes.desktop = {
|
||||||
|
layouts.layout =
|
||||||
|
lib.replaceStrings
|
||||||
|
[ ''<property name="height-request">570</property>'' ]
|
||||||
|
[ ''<property name="height-request">460</property>'' ]
|
||||||
|
(builtins.readFile "${inputs.walker}/resources/themes/default/layout.xml");
|
||||||
|
style = lib.mkBefore (
|
||||||
|
builtins.readFile "${inputs.walker}/resources/themes/default/style.css"
|
||||||
|
+ ''
|
||||||
|
.box-wrapper {
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
|
||||||
|
}
|
||||||
|
.search-container, .item-box, .preview { border-radius: 6px; }
|
||||||
|
.input { padding: 8px 10px; }
|
||||||
|
.item-box { padding: 5px 8px; }
|
||||||
|
.large-icons { -gtk-icon-size: 24px; }
|
||||||
|
.item-image-text { font-size: 24px; }
|
||||||
|
.item-subtext { opacity: 0.75; }
|
||||||
|
.item-quick-activation { padding: 3px 5px; }
|
||||||
|
.keybinds { padding-top: 6px; }
|
||||||
|
.keybind-bind { opacity: 0.65; }
|
||||||
|
''
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
config.providers = {
|
||||||
|
default = walkerDefaults.providers.default;
|
||||||
|
prefixes = walkerDefaults.providers.prefixes ++ [
|
||||||
|
{
|
||||||
|
provider = "bitwarden";
|
||||||
|
prefix = "?";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
--- a/internal/providers/bitwarden/setup.go
|
||||||
|
+++ b/internal/providers/bitwarden/setup.go
|
||||||
|
@@ -34,7 +34,7 @@
|
||||||
|
func Setup() {
|
||||||
|
LoadConfig()
|
||||||
|
|
||||||
|
- initItems()
|
||||||
|
+ // Vault access is initiated by an explicit query, never daemon startup.
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadConfig() {
|
||||||
|
--- a/internal/providers/bitwarden/query.go
|
||||||
|
+++ b/internal/providers/bitwarden/query.go
|
||||||
|
@@ -7,6 +7,7 @@
|
||||||
|
"net"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
+ "sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/abenz1267/elephant/v2/pkg/common"
|
||||||
|
@@ -20,7 +21,24 @@
|
||||||
|
Folder string `json:"folder"`
|
||||||
|
}
|
||||||
|
|
||||||
|
+var itemsMu sync.Mutex
|
||||||
|
+
|
||||||
|
func initItems() {
|
||||||
|
+ itemsMu.Lock()
|
||||||
|
+ defer itemsMu.Unlock()
|
||||||
|
+ initItemsLocked()
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+func items() []RbwItem {
|
||||||
|
+ itemsMu.Lock()
|
||||||
|
+ defer itemsMu.Unlock()
|
||||||
|
+ if cachedItems == nil {
|
||||||
|
+ initItemsLocked()
|
||||||
|
+ }
|
||||||
|
+ return cachedItems
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+func initItemsLocked() {
|
||||||
|
cachedItems = nil
|
||||||
|
cmd := exec.Command("rbw", "list", "--raw")
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
@@ -40,7 +58,7 @@
|
||||||
|
|
||||||
|
entries := []*pb.QueryResponse_Item{}
|
||||||
|
|
||||||
|
- for k, v := range cachedItems {
|
||||||
|
+ for k, v := range items() {
|
||||||
|
var subtexts []string
|
||||||
|
actions := []string{ActionCopyPassword, ActionCopyTotp, ActionSyncVault}
|
||||||
|
if config.AutoTypeSupport {
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
# Company environment
|
||||||
|
|
||||||
|
This capability owns the company-root tools, human workbench environment and
|
||||||
|
persistent read-only company mounts. Garden packaging and company certificates
|
||||||
|
remain in `../yookr-dev/`. Requests, queries, analysis, `uv.lock`, content and
|
||||||
|
runtime state stay in `~/yookr/workbench`.
|
||||||
|
|
||||||
|
Home Manager installs `devenv.nix` and `devenv.yaml` in `~/yookr/workbench`
|
||||||
|
(human credentials), selecting the system's exact nixpkgs store path. The work
|
||||||
|
profile also installs the tools for use at the company root without activation. The devenv CLI
|
||||||
|
uses its own upstream dependency closure; this avoids rebuilding its dependencies
|
||||||
|
against an unsupported pin. Its version is locked by the repository flake.
|
||||||
|
|
||||||
|
## Activation and trust
|
||||||
|
|
||||||
|
After reviewing and activating the configuration on each workstation:
|
||||||
|
|
||||||
|
1. Remove the obsolete `~/yookr/.envrc` and `~/yookr/workbench/.envrc`. Direnv is
|
||||||
|
no longer installed or hooked. Product/personal `.envrc` files remain yours to
|
||||||
|
migrate; this pass does not convert them.
|
||||||
|
2. Run `devenv allow` in `~/yookr/workbench` only. Open a new terminal
|
||||||
|
for the native Zsh hook. Reload/file watching uses upstream defaults.
|
||||||
|
3. `devenv.lock` and `.devenv/` are local generated state, not new configuration
|
||||||
|
owners. Do not commit them into the Nix repository. Retain product locks.
|
||||||
|
4. The human workbench attempts company, live and test resolution independently.
|
||||||
|
`workbench-reload` retries; `workbench-reload --tools-only` clears the variables
|
||||||
|
owned by this loader. Existing processes/editors keep their original environment.
|
||||||
|
|
||||||
|
For a clean, credential-free check use the flake's tools-only `#workbench` shell
|
||||||
|
from a clean parent environment. For native devenv without credential loading,
|
||||||
|
set `WORKBENCH_TOOLS_ONLY=1` before `devenv shell`. Neither method removes arbitrary
|
||||||
|
credentials already inherited from its parent; they are not isolation mechanisms.
|
||||||
|
|
||||||
|
The company root intentionally has no generated devenv environment pending review:
|
||||||
|
upstream's hook does nothing while another devenv shell is active, so an ancestor
|
||||||
|
shell would prevent automatic workbench entry and interfere with project environments.
|
||||||
|
The recommendation is installed tools at the company root, native activation at the
|
||||||
|
workbench, and product-owned environments below `projects/`.
|
||||||
|
|
||||||
|
## Credential provisioning (user-run only)
|
||||||
|
|
||||||
|
The encrypted company document belongs at `modules/secrets/company.yaml` in this
|
||||||
|
repository. It is deliberately absent until you migrate it. Reuse the existing
|
||||||
|
machine age identities; never copy private keys into Git. On each workstation,
|
||||||
|
obtain its public recipient with `age-keygen -y /var/lib/sops/keys.txt`.
|
||||||
|
|
||||||
|
On the machine holding the old credentials, run from this repository:
|
||||||
|
|
||||||
|
```console
|
||||||
|
SOPS_AGE_KEY_FILE="$HOME/.config/sops/age/keys.txt" python3 modules/capabilities/workbench/migrate-credentials.py \
|
||||||
|
"$HOME/.config/yookr/credentials.yaml" modules/secrets/company.yaml \
|
||||||
|
--age 'POLARIS_PUBLIC_AGE_RECIPIENT,ZENITH_PUBLIC_AGE_RECIPIENT'
|
||||||
|
```
|
||||||
|
|
||||||
|
The helper decrypts only in memory, preserves the old file, and refuses to overwrite
|
||||||
|
an existing destination. The new document contains root-level company login and
|
||||||
|
live database URLs for SecretSpec, plus the existing `leafcloud` map for mounts.
|
||||||
|
MySQL certificate verification behavior is preserved. Test credentials are not
|
||||||
|
copied into the new document. Review the encrypted result before a local commit;
|
||||||
|
pushing remains a separate decision. Other machines receive ciphertext through the
|
||||||
|
existing repository. Edit it with `sops edit modules/secrets/company.yaml` using the
|
||||||
|
machine's normal `SOPS_AGE_KEY_FILE=/var/lib/sops/keys.txt`.
|
||||||
|
|
||||||
|
### Test cluster: mapping and login still pending
|
||||||
|
|
||||||
|
No cluster query is needed to build this repository. Before enabling test loading,
|
||||||
|
settle the explicit test context and existing application Secret/namespace/key
|
||||||
|
mappings. The loader expects a `~/.config/workbench/test-secrets.toml` manifest with
|
||||||
|
profile `test`, using only explicit `k8s+secret://SECRET@NAMESPACE` providers and
|
||||||
|
`ref.item` for existing keys. Required exports are:
|
||||||
|
|
||||||
|
- `YOOKR_MYSQL_TEST_DATABASE_URL`, `YOOKR_MONGODB_TEST_DATABASE_URL`
|
||||||
|
- `RABBITMQADMIN_USERNAME`, `RABBITMQADMIN_PASSWORD`
|
||||||
|
|
||||||
|
If applications store URL components separately, the manifest/composition must be
|
||||||
|
adapted after confirming their keys; do not invent field names or change URL escaping.
|
||||||
|
This manifest is a provisioning boundary pending review, not a second global secret store.
|
||||||
|
|
||||||
|
Test loading also requires an explicitly prepared, noninteractive kubeconfig at
|
||||||
|
`$XDG_RUNTIME_DIR/workbench/test-kubeconfig`. No generic login helper is provided:
|
||||||
|
the actual context and exec plugin must be inspected first, then its native or
|
||||||
|
provider-specific cached login flow selected. Do not reimplement Kubernetes' exec
|
||||||
|
credential protocol for an unknown plugin. Until both runtime files exist, test
|
||||||
|
reports unavailable. Shell entry never invokes authentication or opens a login popup.
|
||||||
|
|
||||||
|
SecretSpec exports are captured in memory with stdin closed and a timeout. Errors
|
||||||
|
report only the unavailable source, not provider output or secret values. Sources
|
||||||
|
load independently; unavailable sources clear their old variables. Test never falls
|
||||||
|
back to SOPS, and live never depends on Kubernetes. Native devenv's all-at-once secret
|
||||||
|
resolution is intentionally not used: it would couple their failure behavior.
|
||||||
|
|
||||||
|
## Mounts
|
||||||
|
|
||||||
|
`company-obs.service` and `company-sharepoint.service` are user services on both
|
||||||
|
workstations. Mounts live at `~/yookr/workbench/{obs,sharepoint}`. They are read-only,
|
||||||
|
use `--vfs-cache-mode off`, and retry failures every minute. No background content
|
||||||
|
mirror remains. The existing local SharePoint mirror is preserved, not deleted.
|
||||||
|
Small memory buffers and filesystem metadata are still used.
|
||||||
|
|
||||||
|
OBS uses the company's encrypted `leafcloud` map and machine age key. SharePoint
|
||||||
|
uses the existing native rclone remotes `company-sharepoint` and
|
||||||
|
`company-sharepoint-projecten` in `~/.config/rclone/rclone.conf`; configure/login to
|
||||||
|
these on each workstation with rclone. Tokens remain application-owned outside Git.
|
||||||
|
Before first activation, unmount any old workbench-entry OBS mount. Do not empty or
|
||||||
|
replace nonempty mount directories: move any authored content deliberately first.
|
||||||
|
|
||||||
|
```console
|
||||||
|
systemctl --user restart company-obs company-sharepoint
|
||||||
|
systemctl --user status company-obs company-sharepoint
|
||||||
|
```
|
||||||
|
|
||||||
|
Do not invoke the old workspace `just mount-obs` helper once systemd owns the mount.
|
||||||
|
The old helper/recipes can be removed after the new mounts are accepted in use.
|
||||||
|
Shell exit does not unmount company files. All processes running as your user can
|
||||||
|
read the mounts; these services do not isolate agents.
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
garden ? import ../../yookr-dev/_support/packages.nix { inherit pkgs; },
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
packages = [
|
||||||
|
garden.gardenctl
|
||||||
|
garden.gardenlogin
|
||||||
|
]
|
||||||
|
++ (with pkgs; [
|
||||||
|
k9s
|
||||||
|
kubectl
|
||||||
|
kubelogin-oidc
|
||||||
|
jq
|
||||||
|
just
|
||||||
|
python314
|
||||||
|
rclone
|
||||||
|
sops
|
||||||
|
secretspec
|
||||||
|
util-linux
|
||||||
|
uv
|
||||||
|
]);
|
||||||
|
env = {
|
||||||
|
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [
|
||||||
|
pkgs.stdenv.cc.cc.lib
|
||||||
|
pkgs.zlib
|
||||||
|
];
|
||||||
|
UV_PYTHON = "${pkgs.python314}/bin/python";
|
||||||
|
UV_PYTHON_DOWNLOADS = "never";
|
||||||
|
RABBITMQADMIN_TARGET_HOST = "test.rabbitmq.yookr.org";
|
||||||
|
RABBITMQADMIN_TARGET_PORT = "443";
|
||||||
|
RABBITMQADMIN_USE_TLS = "true";
|
||||||
|
RABBITMQADMIN_NON_INTERACTIVE_MODE = "true";
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
{ inputs, ... }:
|
||||||
|
{
|
||||||
|
flake.modules.homeManager.workbench =
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
home = config.home.homeDirectory;
|
||||||
|
root = "${home}/yookr/workbench";
|
||||||
|
companySecrets = "${home}/.config/nixos/modules/secrets/company.yaml";
|
||||||
|
environmentInputs = builtins.toJSON {
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "path:${inputs.nixpkgs}";
|
||||||
|
git-hooks.url = "path:${inputs.devenv.inputs.git-hooks}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
secretsManifest = (pkgs.formats.toml { }).generate "workbench-secrets.toml" {
|
||||||
|
project = {
|
||||||
|
name = "workbench";
|
||||||
|
revision = "1";
|
||||||
|
};
|
||||||
|
providers.company = "sops://${companySecrets}?age_key_file=/var/lib/sops/keys.txt";
|
||||||
|
profiles =
|
||||||
|
lib.mapAttrs
|
||||||
|
(
|
||||||
|
_: names:
|
||||||
|
lib.genAttrs names (name: {
|
||||||
|
description = name;
|
||||||
|
ref.item = name;
|
||||||
|
providers = [ "company" ];
|
||||||
|
})
|
||||||
|
)
|
||||||
|
{
|
||||||
|
company = [
|
||||||
|
"email"
|
||||||
|
"password"
|
||||||
|
];
|
||||||
|
live = [
|
||||||
|
"YOOKR_MYSQL_LIVE_DATABASE_URL"
|
||||||
|
"YOOKR_MONGODB_LIVE_DATABASE_URL"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
mountObs = pkgs.writeShellApplication {
|
||||||
|
name = "mount-company-obs";
|
||||||
|
runtimeInputs = [
|
||||||
|
pkgs.python3
|
||||||
|
pkgs.rclone
|
||||||
|
pkgs.sops
|
||||||
|
];
|
||||||
|
text = ''
|
||||||
|
export PATH=/run/wrappers/bin:"$PATH"
|
||||||
|
exec python3 ${./mount-obs.py} ${lib.escapeShellArg companySecrets} ${lib.escapeShellArg "${root}/obs"}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
mountSharepoint = pkgs.writeShellApplication {
|
||||||
|
name = "mount-company-sharepoint";
|
||||||
|
runtimeInputs = [
|
||||||
|
pkgs.rclone
|
||||||
|
pkgs.coreutils
|
||||||
|
];
|
||||||
|
text = ''
|
||||||
|
export PATH=/run/wrappers/bin:"$PATH"
|
||||||
|
mkdir -p ${lib.escapeShellArg "${root}/sharepoint"}
|
||||||
|
export RCLONE_CONFIG_SHAREPOINT_TYPE=combine
|
||||||
|
export RCLONE_CONFIG_SHAREPOINT_UPSTREAMS='Algemeen=company-sharepoint: Projecten=company-sharepoint-projecten:'
|
||||||
|
exec rclone mount sharepoint: ${lib.escapeShellArg "${root}/sharepoint"} \
|
||||||
|
--config ${lib.escapeShellArg "${config.xdg.configHome}/rclone/rclone.conf"} \
|
||||||
|
--read-only --vfs-cache-mode off --buffer-size 8M
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
mountService = name: command: {
|
||||||
|
Unit = {
|
||||||
|
Description = "Read-only company ${name} mount";
|
||||||
|
After = [ "network-online.target" ];
|
||||||
|
StartLimitIntervalSec = 0;
|
||||||
|
};
|
||||||
|
Service = {
|
||||||
|
Type = "simple";
|
||||||
|
ExecStart = lib.getExe command;
|
||||||
|
ExecStop = "/run/wrappers/bin/fusermount3 -u ${root}/${name}";
|
||||||
|
Environment = "SOPS_AGE_KEY_FILE=/var/lib/sops/keys.txt";
|
||||||
|
UMask = "0077";
|
||||||
|
Restart = "on-failure";
|
||||||
|
RestartSec = 60;
|
||||||
|
};
|
||||||
|
Install.WantedBy = [ "default.target" ];
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# devenv already installs its bundled SecretSpec CLI in the workstation profile.
|
||||||
|
home.packages =
|
||||||
|
lib.remove pkgs.secretspec (import ./_support/tools.nix { inherit pkgs; }).packages;
|
||||||
|
programs.zsh.initContent = lib.mkAfter ''
|
||||||
|
workbench-reload() {
|
||||||
|
if [[ "''${DEVENV_ROOT:-}" != ${lib.escapeShellArg root} ]]; then
|
||||||
|
print -u2 'Enter the workbench devenv shell before loading credentials.'
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
local exports
|
||||||
|
exports="$(${pkgs.python3}/bin/python3 ${./load-secrets.py} ${secretsManifest} "$@")" || return
|
||||||
|
eval "$exports"
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
|
||||||
|
home.file."yookr/workbench/devenv.yaml".text = environmentInputs;
|
||||||
|
home.file."yookr/workbench/devenv.nix".text = ''
|
||||||
|
{ pkgs, ... }:
|
||||||
|
let tools = import ${./_support/tools.nix} {
|
||||||
|
inherit pkgs;
|
||||||
|
garden = import ${../yookr-dev/_support/packages.nix} { inherit pkgs; };
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
inherit (tools) packages env;
|
||||||
|
enterShell = ${lib.strings.escapeNixString ''
|
||||||
|
if [ "''${WORKBENCH_TOOLS_ONLY:-0}" = 1 ]; then
|
||||||
|
eval "$(python3 ${./load-secrets.py} ${secretsManifest} --tools-only)"
|
||||||
|
else
|
||||||
|
eval "$(python3 ${./load-secrets.py} ${secretsManifest})"
|
||||||
|
fi
|
||||||
|
''};
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
systemd.user.services = {
|
||||||
|
company-obs = mountService "obs" mountObs;
|
||||||
|
company-sharepoint = mountService "sharepoint" mountSharepoint;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
perSystem =
|
||||||
|
{ pkgs, ... }:
|
||||||
|
let
|
||||||
|
tools = import ./_support/tools.nix { inherit pkgs; };
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# A credential-free build target for the same tools used by native devenv.
|
||||||
|
devShells.workbench = pkgs.mkShell (tools.env // { inherit (tools) packages; });
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
"""Emit shell exports for independent sources; never print provider errors or values to stderr."""
|
||||||
|
import argparse
|
||||||
|
import concurrent.futures
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import shlex
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument('manifest', type=Path)
|
||||||
|
parser.add_argument('--tools-only', action='store_true')
|
||||||
|
args = parser.parse_args()
|
||||||
|
groups = {
|
||||||
|
'company': ['email', 'password'],
|
||||||
|
'live': ['YOOKR_MYSQL_LIVE_DATABASE_URL', 'YOOKR_MONGODB_LIVE_DATABASE_URL'],
|
||||||
|
'test': ['YOOKR_MYSQL_TEST_DATABASE_URL', 'YOOKR_MONGODB_TEST_DATABASE_URL',
|
||||||
|
'RABBITMQADMIN_USERNAME', 'RABBITMQADMIN_PASSWORD'],
|
||||||
|
}
|
||||||
|
|
||||||
|
def load(group):
|
||||||
|
env = os.environ.copy()
|
||||||
|
# Explicit manifests/profiles/providers must not inherit a user's override.
|
||||||
|
for name in ('SECRETSPEC_PROVIDER', 'SECRETSPEC_PROFILE', 'SECRETSPEC_SCOPE'):
|
||||||
|
env.pop(name, None)
|
||||||
|
if group == 'test':
|
||||||
|
# A dedicated, explicitly provisioned test kubeconfig is mandatory.
|
||||||
|
kubeconfig = Path(os.environ.get('XDG_RUNTIME_DIR', '/nonexistent')) / 'workbench/test-kubeconfig'
|
||||||
|
manifest = Path.home() / '.config/workbench/test-secrets.toml'
|
||||||
|
if not kubeconfig.is_file() or not manifest.is_file():
|
||||||
|
return group, None
|
||||||
|
env['KUBECONFIG'] = str(kubeconfig)
|
||||||
|
else:
|
||||||
|
manifest = args.manifest
|
||||||
|
try:
|
||||||
|
result = subprocess.run(
|
||||||
|
['secretspec', '--file', str(manifest), 'export', '--profile', group, '--format', 'json'],
|
||||||
|
env=env, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL,
|
||||||
|
timeout=20, check=True, text=True)
|
||||||
|
values = json.loads(result.stdout)
|
||||||
|
if not all(isinstance(values.get(key), str) and values[key] for key in groups[group]):
|
||||||
|
return group, None
|
||||||
|
return group, {key: values[key] for key in groups[group]}
|
||||||
|
except (OSError, ValueError, subprocess.SubprocessError):
|
||||||
|
return group, None
|
||||||
|
|
||||||
|
# Clear inherited target values before attempting a reload, including on failure.
|
||||||
|
for keys in groups.values():
|
||||||
|
for key in keys:
|
||||||
|
print('unset ' + key)
|
||||||
|
if args.tools_only:
|
||||||
|
for group in groups:
|
||||||
|
print('export WORKBENCH_' + group.upper() + '_STATUS=disabled')
|
||||||
|
else:
|
||||||
|
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
|
||||||
|
for group, values in executor.map(load, groups):
|
||||||
|
status = 'ready' if values is not None else 'unavailable'
|
||||||
|
print('export WORKBENCH_' + group.upper() + '_STATUS=' + status)
|
||||||
|
if values:
|
||||||
|
for key, value in values.items():
|
||||||
|
print('export ' + key + '=' + shlex.quote(value))
|
||||||
|
print(f'workbench: {group} {status}', file=sys.stderr)
|
||||||
|
print('Retry after provisioning/login: workbench-reload. Clean tools: workbench-reload --tools-only.', file=sys.stderr)
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""User-run migration: decrypt in memory, reshape, encrypt for both machine keys."""
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import subprocess
|
||||||
|
from urllib.parse import quote
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument('source', type=Path)
|
||||||
|
parser.add_argument('destination', type=Path)
|
||||||
|
parser.add_argument('--age', required=True, help='Comma-separated public age recipients for both machines')
|
||||||
|
args = parser.parse_args()
|
||||||
|
if args.destination.exists():
|
||||||
|
parser.error('Destination exists; refusing to overwrite it')
|
||||||
|
|
||||||
|
def url(scheme, database):
|
||||||
|
authority = quote(database['username'], safe='') + ':' + quote(database['password'], safe='')
|
||||||
|
authority += '@' + database['host']
|
||||||
|
if database.get('port'):
|
||||||
|
authority += ':' + str(database['port'])
|
||||||
|
return scheme + '://' + authority
|
||||||
|
|
||||||
|
try:
|
||||||
|
old = json.loads(subprocess.check_output(
|
||||||
|
['sops', 'decrypt', '--output-type', 'json', str(args.source)], stderr=subprocess.DEVNULL))
|
||||||
|
new = {
|
||||||
|
'email': old['company_login']['email'],
|
||||||
|
'password': old['company_login']['password'],
|
||||||
|
'YOOKR_MYSQL_LIVE_DATABASE_URL': url('mariadb', old['databases']['mysql']['live']) + '?ssl-verify-server-cert=0',
|
||||||
|
'YOOKR_MONGODB_LIVE_DATABASE_URL': url('mongodb+srv', old['databases']['mongodb']['live']),
|
||||||
|
'leafcloud': old['leafcloud'],
|
||||||
|
}
|
||||||
|
encrypted = subprocess.check_output(
|
||||||
|
['sops', 'encrypt', '--input-type', 'json', '--output-type', 'yaml',
|
||||||
|
'--age', args.age, '/dev/stdin'], input=json.dumps(new).encode(), stderr=subprocess.DEVNULL)
|
||||||
|
os.umask(0o077)
|
||||||
|
with args.destination.open('xb') as output:
|
||||||
|
output.write(encrypted)
|
||||||
|
except (subprocess.CalledProcessError, KeyError, ValueError, OSError):
|
||||||
|
raise SystemExit('Migration failed; no plaintext was written. Check source schema, keys and recipients.')
|
||||||
|
print('Encrypted company document created. Original credentials were preserved.')
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
"""Foreground read-only OBS mount; systemd owns lifecycle and retries."""
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
projects = json.loads(subprocess.check_output(
|
||||||
|
['sops', 'decrypt', '--extract', '["leafcloud"]', '--output-type', 'json', sys.argv[1]],
|
||||||
|
stderr=subprocess.DEVNULL))
|
||||||
|
if not projects:
|
||||||
|
raise ValueError('No projects')
|
||||||
|
env = os.environ.copy()
|
||||||
|
upstreams = []
|
||||||
|
for index, (project, credentials) in enumerate(projects.items()):
|
||||||
|
if not re.fullmatch(r'[A-Za-z0-9_-]+', project):
|
||||||
|
raise ValueError('Invalid project name')
|
||||||
|
remote = f'obs_project_{index}'
|
||||||
|
options = dict(type='s3', provider='Other', region='europe-nl-ams1',
|
||||||
|
endpoint='https://leafcloud.store', force_path_style='true',
|
||||||
|
access_key_id=credentials['access_key_id'],
|
||||||
|
secret_access_key=credentials['secret_access_key'])
|
||||||
|
env.update({f'RCLONE_CONFIG_{remote.upper()}_{key.upper()}': str(value)
|
||||||
|
for key, value in options.items()})
|
||||||
|
upstreams.append(f'{project}={remote}:')
|
||||||
|
env['RCLONE_CONFIG_OBS_TYPE'] = 'combine'
|
||||||
|
env['RCLONE_CONFIG_OBS_UPSTREAMS'] = ' '.join(upstreams)
|
||||||
|
mount = Path(sys.argv[2])
|
||||||
|
mount.mkdir(parents=True, exist_ok=True)
|
||||||
|
os.execvpe('rclone', ['rclone', 'mount', 'obs:', str(mount), '--config', '/dev/null',
|
||||||
|
'--read-only', '--vfs-cache-mode', 'off', '--buffer-size', '8M'], env)
|
||||||
|
except (subprocess.CalledProcessError, KeyError, ValueError, OSError):
|
||||||
|
raise SystemExit('OBS mount unavailable: check company SOPS provisioning and the machine age key.')
|
||||||
File renamed without changes.
@@ -2,9 +2,10 @@
|
|||||||
flake.modules.homeManager.yookr-tools =
|
flake.modules.homeManager.yookr-tools =
|
||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
let
|
let
|
||||||
tools = import ./yookr-dev/_packages.nix { inherit pkgs; };
|
tools = import ./_support/packages.nix { inherit pkgs; };
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
programs.zsh.initContent = "source <(gardenctl rc zsh --no-completion)";
|
||||||
home.packages = [
|
home.packages = [
|
||||||
tools.gardenctl
|
tools.gardenctl
|
||||||
tools.gardenlogin
|
tools.gardenlogin
|
||||||
@@ -13,8 +14,8 @@
|
|||||||
|
|
||||||
flake.modules.nixos.yookr-dev = {
|
flake.modules.nixos.yookr-dev = {
|
||||||
security.pki.certificateFiles = [
|
security.pki.certificateFiles = [
|
||||||
./yookr-dev/zenith-rootCA.pem
|
./zenith-rootCA.pem
|
||||||
./yookr-dev/polaris-rootCA.pem
|
./polaris-rootCA.pem
|
||||||
];
|
];
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [
|
networking.firewall.allowedTCPPorts = [
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
{
|
|
||||||
perSystem =
|
|
||||||
{ pkgs, ... }:
|
|
||||||
let
|
|
||||||
tools = import ./_packages.nix { inherit pkgs; };
|
|
||||||
in
|
|
||||||
{
|
|
||||||
# Tooling only: no credential loading, mounts, or Python dependency installs.
|
|
||||||
devShells.workbench = pkgs.mkShell {
|
|
||||||
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [
|
|
||||||
pkgs.stdenv.cc.cc.lib
|
|
||||||
pkgs.zlib
|
|
||||||
];
|
|
||||||
UV_PYTHON = "${pkgs.python314}/bin/python";
|
|
||||||
UV_PYTHON_DOWNLOADS = "never";
|
|
||||||
packages = [
|
|
||||||
tools.gardenctl
|
|
||||||
tools.gardenlogin
|
|
||||||
]
|
|
||||||
++ (with pkgs; [
|
|
||||||
k9s
|
|
||||||
kubectl
|
|
||||||
kubelogin-oidc
|
|
||||||
jq
|
|
||||||
just
|
|
||||||
python314
|
|
||||||
rclone
|
|
||||||
sops
|
|
||||||
util-linux
|
|
||||||
uv
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -37,16 +37,13 @@ in
|
|||||||
flake.modules.nixos.zenith = {
|
flake.modules.nixos.zenith = {
|
||||||
imports = [
|
imports = [
|
||||||
nixosModules.workstation-base
|
nixosModules.workstation-base
|
||||||
|
nixosModules.openssh
|
||||||
nixosModules.laptop-power
|
nixosModules.laptop-power
|
||||||
nixosModules.sharepoint-reference
|
|
||||||
./_hardware.nix
|
./_hardware.nix
|
||||||
inputs.nixos-hardware.nixosModules.lenovo-yoga-7-14ARH7-amdgpu
|
inputs.nixos-hardware.nixosModules.lenovo-yoga-7-14ARH7-amdgpu
|
||||||
];
|
];
|
||||||
|
|
||||||
services.fwupd.enable = true;
|
services.fwupd.enable = true;
|
||||||
services.teamviewer.enable = true;
|
services.openssh.openFirewall = false;
|
||||||
# Temporary Xorg session for remote support.
|
|
||||||
# services.xserver.enable = true;
|
|
||||||
# services.xserver.desktopManager.xfce.enable = true;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -13,6 +13,7 @@ in
|
|||||||
nixosModules.facts
|
nixosModules.facts
|
||||||
inputs.home-manager.nixosModules.home-manager
|
inputs.home-manager.nixosModules.home-manager
|
||||||
nixosModules.nix
|
nixosModules.nix
|
||||||
|
nixosModules.tailscale
|
||||||
nixosModules.locale
|
nixosModules.locale
|
||||||
nixosModules.sops
|
nixosModules.sops
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ in
|
|||||||
flake.modules.homeManager.work = {
|
flake.modules.homeManager.work = {
|
||||||
imports = [
|
imports = [
|
||||||
homeModules.yookr-tools
|
homeModules.yookr-tools
|
||||||
|
homeModules.workbench
|
||||||
homeModules.work-git
|
homeModules.work-git
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ in
|
|||||||
nixosModules.adb
|
nixosModules.adb
|
||||||
nixosModules.audio
|
nixosModules.audio
|
||||||
nixosModules.bluetooth
|
nixosModules.bluetooth
|
||||||
|
nixosModules.file-management
|
||||||
nixosModules.flatpak
|
nixosModules.flatpak
|
||||||
nixosModules.fonts
|
nixosModules.fonts
|
||||||
nixosModules.network-manager
|
nixosModules.network-manager
|
||||||
@@ -49,7 +50,7 @@ in
|
|||||||
homeModules.xdg
|
homeModules.xdg
|
||||||
homeModules.workstation-apps
|
homeModules.workstation-apps
|
||||||
homeModules.vivaldi
|
homeModules.vivaldi
|
||||||
homeModules.nautilus
|
homeModules.file-management
|
||||||
homeModules.imv
|
homeModules.imv
|
||||||
homeModules.sioyek
|
homeModules.sioyek
|
||||||
homeModules.discord
|
homeModules.discord
|
||||||
|
|||||||
+6
-1
@@ -58,12 +58,15 @@ def main():
|
|||||||
|
|
||||||
snapshot()
|
snapshot()
|
||||||
flake = f"path:{source}"
|
flake = f"path:{source}"
|
||||||
nix = ["nix", "--quiet"]
|
nix = ["nix", "--quiet", "--accept-flake-config"]
|
||||||
locked = ["--no-update-lock-file"]
|
locked = ["--no-update-lock-file"]
|
||||||
# The repository currently exposes only x86_64-linux outputs.
|
# The repository currently exposes only x86_64-linux outputs.
|
||||||
nix_files = [str(ROOT / name) for name in files if name.endswith(".nix")]
|
nix_files = [str(ROOT / name) for name in files if name.endswith(".nix")]
|
||||||
run("format", nix + ["run", *locked, f"{flake}#formatter.x86_64-linux", "--", *nix_files])
|
run("format", nix + ["run", *locked, f"{flake}#formatter.x86_64-linux", "--", *nix_files])
|
||||||
snapshot()
|
snapshot()
|
||||||
|
# Upstream devenv evaluates generated Nix (including cabal2nix). Realize
|
||||||
|
# those evaluation dependencies before flake check enters read-only mode.
|
||||||
|
run("prepare-devenv", nix + ["eval", *locked, "--raw", f"{flake}#packages.x86_64-linux.devenv.drvPath"])
|
||||||
run("check", nix + ["flake", "check", "--no-build", *locked, flake])
|
run("check", nix + ["flake", "check", "--no-build", *locked, flake])
|
||||||
hosts_file = run_dir / "hosts.json"
|
hosts_file = run_dir / "hosts.json"
|
||||||
# Keep machine-readable output separate from Nix diagnostics.
|
# Keep machine-readable output separate from Nix diagnostics.
|
||||||
@@ -90,5 +93,7 @@ def main():
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
try:
|
try:
|
||||||
main()
|
main()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
sys.exit("Validation interrupted; completed stages do not establish a full pass.")
|
||||||
except (OSError, ValueError, RuntimeError, subprocess.CalledProcessError) as error:
|
except (OSError, ValueError, RuntimeError, subprocess.CalledProcessError) as error:
|
||||||
sys.exit(str(error))
|
sys.exit(str(error))
|
||||||
Reference in new issue
Block a user