diff options
| author | Szymon Szukalski <szymon@szymonszukalski.com> | 2026-04-08 09:40:14 +1000 |
|---|---|---|
| committer | Szymon Szukalski <szymon@szymonszukalski.com> | 2026-04-08 09:40:14 +1000 |
| commit | 64b7fea64e02d482dd189f831813db19ed266118 (patch) | |
| tree | 739fda2c7c44a4912f0bf8ecc777b3a20fe3d474 | |
| parent | d234df7277a53333204af44e6d02b76606067314 (diff) | |
docs: align org workflow rules
| -rw-r--r-- | AGENTS.md | 13 | ||||
| -rw-r--r-- | README.md | 93 | ||||
| -rw-r--r-- | config.org | 33 |
3 files changed, 102 insertions, 37 deletions
@@ -6,13 +6,18 @@ This repository is for the creation and maintenance of Emacs 30 configuration fi ## Repository Layout -- `config.org` is the single hand-edited source of truth for the configuration. +- `config.org` is the single hand-edited source of truth for Emacs configuration. - `init.el` and `early-init.el` are generated from `config.org` and should not be edited directly. - Structure the literate config by startup responsibility first, then by workflow domain. - The current Org workflow lives under `~/org/` with `daily/`, `projects/`, `areas/`, `areas/people/people.org`, `resources/`, and `archives/`. +- `~/org/` is external to this repository and must already exist. +- The configuration may open files in `~/org/`, but it must not create directories, create files, or validate note structure. +- `~/org/moc.org` is a normal note. The configuration may open it, but it must not create or manage it. - Daily notes stay as plain Org files under `~/org/daily/`; longer-lived notes are handled through Denote in the same root. -- Agenda files are discovered dynamically from the project, area, and resource directories rather than from a fixed file list. -- The config also includes a small gptel workflow that uses GitHub Copilot as the backend. +- Agenda files are discovered by recursively scanning `.org` files under `~/org/projects/`, `~/org/areas/`, and `~/org/resources/`. +- Agenda discovery must exclude `~/org/daily/` and `~/org/archives/`. +- PARA is the organising model for durable notes, and folder placement carries meaning. +- The config includes an experimental `gptel` setup that uses GitHub Copilot as the backend. - Do not treat `auto-save-list/` as source content. ## Editing Expectations @@ -47,6 +52,8 @@ This repository is for the creation and maintenance of Emacs 30 configuration fi - Document non-obvious conventions close to the relevant configuration in `config.org`. - Update `README.md` whenever configuration or workflow changes alter package usage, startup behavior, keybindings, directory layout, capture flow, or other documented behavior. - `README.md` must describe the current configuration truthfully. Do not leave stale documentation behind and do not document planned behavior as current behavior. +- Keep README and AGENTS consistent. State rules explicitly and avoid hidden or heuristic behavior in documentation. +- Use `~/org` consistently when describing the external notes directory. - Before claiming a change is complete or asking to commit it, review whether `README.md` needs an update; if it does not, say so explicitly in the summary. - Update AGENTS.md when the repo workflow, Org layout, or verification expectations materially change. - Keep AGENTS.md concise and update it only when the repository structure or working rules actually change. @@ -1,12 +1,24 @@ # Emacs Configuration -This repository contains a literate Emacs configuration built around Org mode, Denote, a PARA-style note layout, and a small completion stack. The hand-edited source is `config.org`; `init.el` and `early-init.el` are generated from it. +This repository contains a literate Emacs configuration built around Org mode, Denote, a PARA-style note layout, and a small completion stack. The hand-edited configuration source is `config.org`; `init.el` and `early-init.el` are generated from it. + +## System Model + +This repository configures Emacs. It does not define, create, or validate the `~/org` note system. + +- `config.org` is the source of truth for Emacs configuration only. +- `~/org` is external to this repository and must already exist. +- The configuration may open files in `~/org`, but it must not create directories, create files, or validate note structure. +- `~/org/moc.org` is a normal note. The configuration may open it, but it must not create or manage it. +- PARA is the organising model for durable notes. Folder placement carries meaning, and workflows must respect that placement. +- The system optimises for speed of capture and minimal friction. +- The system must prefer explicit rules over implicit behaviour and must avoid over-structuring, manual overhead, and inconsistency. ## Emacs Setup ### Source of truth and generated files -`config.org` is the only file intended for manual configuration edits. The generated startup files are: +`config.org` is the only file intended for manual Emacs configuration edits. The generated startup files are: - `early-init.el` for settings that must exist before the first GUI frame. - `init.el` for the main runtime configuration. @@ -23,18 +35,18 @@ The current setup uses these packages and built-in modules: - `org` and `org-capture` for agenda, capture, daily notes, and the literate configuration itself. - `denote` for durable notes, naming, keywords, and linking. -- `git-auto-commit-mode` for automatic note commits on save inside the notes repo. +- `git-auto-commit-mode` for optional automatic commits inside `~/org` when enabled by directory-local settings. - `vertico` for minibuffer completion UI. - `orderless` for flexible completion matching. - `marginalia` for minibuffer annotations. -- `gptel` with the GitHub Copilot backend for chat and rewrite workflows inside Emacs. +- `gptel` with the GitHub Copilot backend, currently being trialled as an experimental tool rather than a defined workflow. - `dired` with a macOS-safe `ls` configuration. - `time` for the modeline clock. - `modus-themes`, using `modus-vivendi` in the current config. ### Org mode and note layout -The note system lives under `~/org/` and is organized like this: +The note system lives under `~/org/` and is organised like this: - `daily/` for plain daily Org files. - `projects/` for project notes. @@ -43,9 +55,15 @@ The note system lives under `~/org/` and is organized like this: - `resources/` for reference material. - `archives/` for archived notes. -This is a PARA-style layout, but the agenda is intentionally narrower than the full tree. Agenda files are discovered dynamically from `projects/` and `areas/` only. Daily notes, archives, and resources are excluded from the agenda scan. +This is a PARA-style layout. Folder placement carries meaning. Denote keywords are used sparingly, with `project` kept as the only built-in structural keyword because project titles are often ambiguous outside their folder. + +### Agenda Rules -Folder placement carries most of the structural meaning in this setup. Denote keywords are used sparingly, with `project` kept as the only built-in structural keyword because project titles are often ambiguous outside their folder. +The agenda is rule-based. + +- The agenda must include recursive scans of `.org` files under `~/org/projects/`, `~/org/areas/`, and `~/org/resources/`. +- The agenda must exclude `~/org/daily/` and `~/org/archives/`. +- The agenda must use recursive discovery and explicit include and exclude rules rather than heuristic selection. ### Completion setup @@ -56,15 +74,29 @@ The minibuffer stack is intentionally small: - `marginalia` adds annotations. - `corfu` handles in-buffer completion popups for text and Org buffers. -Name entry uses fixed abbrevs plus the rolodex: +## People System + +The people system is a structured rolodex rooted at `~/org/areas/people/people.org`. + +- Each top-level heading represents one person. +- Entries are strictly structured around heading text and properties. +- The system generates abbrevs from the rolodex. +- The system provides canonical-name completion through a CAPF. +- The system provides reporting views grouped by person properties. +- The system rebuilds on any rolodex change, whether the change comes from manual editing or from a command. +- The rolodex must remain up to date after changes. +- Failures must surface visibly. The system must not silently fall back to stale state. +- `CURRENT_FOCUS` must stay short and phrase-like so summaries and completion annotations remain readable. + +Name entry uses fixed abbrevs plus the people rolodex: - `abbrev` provides deterministic one-shot shortcuts for fixed name expansions. -- people-specific abbrevs are generated dynamically from top-level cards in `~/org/areas/people/people.org`. -- a CAPF feeds Corfu canonical names from `people.org`, while alias matching stays available for lookup and completion. +- people-specific abbrevs are generated from top-level cards in `~/org/areas/people/people.org`. +- a CAPF feeds Corfu canonical names from `~/org/areas/people/people.org`, while alias matching stays available for lookup and completion. - Marginalia annotates person candidates with `role | location | engagement | current focus`. -- `M-x ss/people-open` opens `~/org/areas/people/people.org` in overview mode. +- `M-x ss/people-open` opens `~/org/areas/people/people.org` in overview mode through `ss/people-overview`. - `M-x ss/people-find` opens a person card narrowed to that subtree. -- `M-x ss/people-overview` exits card view by widening and restoring the overview. +- `M-x ss/people-overview` opens the rolodex in overview mode, resetting the file by widening and restoring the overview when leaving card view. - `M-x ss/people-insert-name` inserts the canonical name at point. - `M-x ss/people-insert-summary` inserts a compact single-line summary at point. - `M-x ss/people-add` adds a new person card directly to `~/org/areas/people/people.org`. @@ -95,27 +127,44 @@ emacs --batch -Q --load ./init.el ### MOC -There is a central `~/org/moc.org` note. It is a deliberately small, curated navigation surface for the notes system rather than an exhaustive index or system of record, and the config assumes the file already exists. +`~/org/moc.org` is a normal note. It serves as a small curated navigation surface rather than an exhaustive index or system of record, and the configuration assumes the file already exists. -The MOC opens automatically on Emacs startup through startup-hook behavior, but the config now just opens the file directly rather than creating it. `C-c n M` opens it manually at any time. +The configuration may open the MOC automatically on startup, and `C-c n M` opens it manually. The configuration must not create or manage the file. Its Quick Access section provides actionable links for opening the agenda, today's note, capture, and a new note, while the rest of the file stays lightweight and curated around active projects, areas, and a few high-leverage resources. +### Capture Model + +The capture model has two distinct modes. + ### Daily notes -Daily notes are plain Org files in `~/org/daily/`, named by date. When a daily note is created through the config, it starts with these headings: +Daily notes are plain Org files in `~/org/daily/`, named by date. The workflow expects these headings: - `Tasks` - `Notes` - `Open Loops` -Daily capture stays fast without routing everything through Denote. +Daily notes are a work journal. They use light structure and are optimised for speed. + +### Durable notes + +Durable notes use Denote and live in the PARA directories under `~/org/`. + +- Durable notes are created through capture plus Denote. +- Durable notes are structured at creation time. +- Folder placement carries meaning. +- The workflow must respect PARA placement rather than relying on later manual cleanup. ### Agenda usage -The agenda is opened through `ss/open-agenda`, bound to `C-c a`. That command explicitly loads `org-agenda`, and the config refreshes `org-agenda-files` immediately before each `org-agenda` invocation so the agenda sees the current PARA files without relying on a fixed file list. +The agenda is opened through `ss/open-agenda`, bound to `C-c a`. That command explicitly loads `org-agenda`, and the config refreshes `org-agenda-files` immediately before each `org-agenda` invocation. + +The agenda scan is explicit: -This means the agenda reflects the current project and area files at runtime instead of relying on a fixed file list. Daily notes, archives, and resources are outside the agenda scan. +- It recursively includes `.org` files from `~/org/projects/`, `~/org/areas/`, and `~/org/resources/`. +- It excludes `~/org/daily/` and `~/org/archives/`. +- It does not rely on heuristics. ### Capture flow @@ -129,6 +178,7 @@ This means the agenda reflects the current project and area files at runtime ins Daily task capture writes under `Tasks`. Daily note capture and daily meeting capture both write under `Notes`, and the meeting template prefixes the heading with a timestamp and the word `meeting`. Denote captures still prompt for title, keywords, and subdirectory placement where appropriate, but folder placement does most of the classification work. The project capture template prepopulates the `project` keyword. Area and resource captures do not inject structural keywords automatically, and there is no Denote-backed meeting capture template. + The people rolodex is intentionally outside `org-capture`: `M-x ss/people-add` writes a compact card directly into `~/org/areas/people/people.org`, keeping the rolodex as a fast reference file instead of another capture sink. ### Note creation and linking @@ -143,7 +193,6 @@ Denote handles long-lived notes. The main bindings are: - `C-c n i` to insert a canonical person name. - `C-c n I` to insert a compact person summary. - `C-c n L` to show people grouped by location. -- `C-c n m` to create a PARA subdirectory from the minibuffer before capturing into it. - `C-c n d` to open today's daily note. - `C-c n o` to restore the rolodex overview. - `C-c n O` to show people grouped by role. @@ -155,11 +204,11 @@ Keyword prompts and directory placement are part of the workflow, not an afterth ### Automatic note commits -The notes tree can opt into `git-auto-commit-mode` through a directory-local file at `~/org/.dir-locals.el`. In the current setup, the Emacs config installs the package and configures shell command chaining based on the active shell, while the notes repository carries its own auto-commit policy in directory locals. +The configuration provides `git-auto-commit-mode` capability. Behaviour is defined in `~/org/.dir-locals.el`. -When enabled for the notes tree, saving a file in `~/org/` makes Emacs try to commit that change to the notes repository. In the current `~/org/.dir-locals.el`, new files are added automatically, commits are debounced by 60 seconds, automatic pushing is enabled, and the default commit message is a timestamp in the form `Auto-commit: YYYY-MM-DD HH:MM:SS`. +When enabled in `~/org/.dir-locals.el`, saving a file in `~/org/` makes Emacs try to commit that change. The configuration must not enforce policy for add, push, debounce, or commit-message behaviour. -Place this file at the root of the notes repository: +Place this file at `~/org/.dir-locals.el`: ```emacs-lisp ((nil . @@ -277,14 +277,19 @@ annotations. (global-corfu-mode 1)) #+end_src -* Name shortcuts +* People rolodex -The people workflow is a lightweight rolodex backed by a single =~/org/areas/people/people.org= -file. Each top-level heading is a compact card with properties for lookup, -completion, reports, and abbrevs. Abbrev remains the fast path for names you -type all the time, while CAPF plus Corfu remains the discovery path. The -machine-facing layer only reads heading text and properties; the =Context= and -=TODOs= sections stay human-facing notes. +The people workflow is a lightweight rolodex backed by the canonical +=~/org/areas/people/people.org= file. Each top-level heading is a compact card +with properties for lookup, completion, reports, and abbrevs. Abbrev remains +the fast path for names you type all the time, while CAPF plus Corfu remains +the discovery path. The machine-facing layer only reads heading text and +properties; the =Context= and =TODOs= sections stay human-facing notes. + +The rolodex is designed around =ss/people-overview=: opening the file starts in +overview mode, direct visits reset back to overview mode, and exiting card view +means widening the buffer and restoring that overview. Keep =CURRENT_FOCUS= +short and phrase-like so summaries and completion annotations stay readable. #+begin_src emacs-lisp (require 'seq) @@ -497,7 +502,7 @@ machine-facing layer only reads heading text and properties; the =Context= and t)))) (defun ss/people-overview () - "Show `ss/people-file' in overview mode." + "Open `ss/people-file' in overview mode, widening first when needed." (interactive) (unless (and buffer-file-name (string= (file-truename buffer-file-name) @@ -509,7 +514,7 @@ machine-facing layer only reads heading text and properties; the =Context= and (org-cycle-hide-drawers 'all)) (defun ss/people-open () - "Open the rolodex in overview mode." + "Open the people rolodex by delegating to `ss/people-overview'." (interactive) (ss/people-overview)) @@ -527,7 +532,7 @@ machine-facing layer only reads heading text and properties; the =Context= and (file-truename ss/people-file)))) (defun ss/people--open-entry (entry) - "Open the people rolodex file and narrow to ENTRY." + "Open the people rolodex file, then narrow to ENTRY for card view." (find-file (ss/people--ensure-file)) (widen) (let ((position (org-find-exact-headline-in-buffer @@ -580,7 +585,10 @@ machine-facing layer only reads heading text and properties; the =Context= and (insert "#+title: " title "\n\n") (dolist (group groups) (insert "* " (car group) "\n") - (dolist (entry (cdr group)) + (dolist (entry (sort (copy-sequence (cdr group)) + (lambda (left right) + (string< (ss/people--entry-name left) + (ss/people--entry-name right))))) (insert "- " (ss/people--display entry) "\n"))) (goto-char (point-min)) (read-only-mode 1) @@ -703,6 +711,7 @@ machine-facing layer only reads heading text and properties; the =Context= and (skip-syntax-backward "w_") (let ((beg (point))) (when (< beg end) + ;; Verify this in real Org/text writing buffers, not just by inspection. (let ((annotation (lambda (candidate) (when-let ((entry (ss/people--entry-by-name candidate))) @@ -723,7 +732,7 @@ machine-facing layer only reads heading text and properties; the =Context= and (add-hook 'completion-at-point-functions #'ss/people-capf nil t))) (defun ss/people--maybe-overview-buffer () - "Reset the people rolodex file to overview when visiting it directly." + "Reset the people rolodex buffer to overview when visiting it directly." (when (and buffer-file-name (string= (file-truename buffer-file-name) (file-truename ss/people-file))) |
