Skip to content

Commit cc3102a

Browse files
⚙️ [Maintenance]: Documentation site migrated to Zensical (#31)
The documentation site is now built with [Zensical](https://zensical.org/) instead of Material for MkDocs. The Blog section has been removed from the site and navigation. All other documentation pages remain accessible at their current URLs, now served by Zensical's `modern` theme. - Fixes #30 ## Removed: Blog section The Blog section and all its content have been removed from the site and navigation. The RSS feed and social preview cards, which depended on third-party plugins not yet available in Zensical, have also been removed. These features are tracked on Zensical's roadmap and can be re-enabled once the corresponding native modules ship. ## Changed: Documentation site built with Zensical The site is now generated by [Zensical](https://zensical.org/), the next-generation platform built by the creators of Material for MkDocs. The `modern` theme variant (Zensical's default) is active. The `overrides/` customizations and `includes/` snippets carry over unchanged, as Zensical's HTML structure is compatible with both theme variants. ## Technical Details **`mkdocs.yml` → `zensical.toml`** All settings translated to native TOML under the `[project]` scope. The `mkdocs.yml` compatibility shim was not used. `modern` is the Zensical default, so no `variant` key is set. **Plugins** Five Tier 2 plugins dropped entirely: `git-committers`, `git-revision-date-localized`, `rss`, `social` (via `mkdocs-material[imaging]`), and `table-reader` — all on Zensical's Tier 2 backlog and not yet available as native modules. Dependent site features (contributor avatars, last-modified dates, RSS feed, social preview cards) are removed with them. `meta` (Tier 1) and `search` (built-in default) are retained. **Blog content deleted** `docs/Blog/index.md`, `docs/Blog/.authors.yml`, `docs/Blog/Posts/test.md`, `docs/Blog/Posts/.meta.yml` — all existed solely as blog plugin inputs. **`Docs.yml` CI workflow rewritten** Full replacement with Zensical's recommended GitHub Pages pattern: `configure-pages` → `checkout` → `setup-python` → `pip install zensical` → `zensical build --clean` → `upload-pages-artifact` → `deploy-pages`. `MATERIAL_FOR_MKDOCS_INSIDER_PAT`, `MKDOCS_GIT_COMMITTERS_APIKEY`, the `PSModule/GitHub-Script` connect step, and all plugin install steps removed. `contents: write` downgraded to `contents: read`. `uv` adoption deferred per planning decision. **Implementation plan progress:** All four groups from issue #30 Section 3 complete in this PR — prep (create `zensical.toml`), prep (remove Blog content), migrate (update `Docs.yml`), cleanup (delete `mkdocs.yml`). The four groups ship atomically because each intermediate state would leave the repo in a broken build. --------- Co-authored-by: psmodule-s-scribbler <199736790+psmodule-s-scribbler@users.noreply.github.com>
1 parent 3b47749 commit cc3102a

38 files changed

Lines changed: 667 additions & 477 deletions

.github/dependabot.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ updates:
1212
- github-actions
1313
schedule:
1414
interval: weekly
15+
cooldown:
16+
default-days: 7

.github/linters/.codespellrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[codespell]
2+
skip = ./.github/linters
3+
ignore-words-list = afterall

.github/linters/.powershell-psscriptanalyzer.psd1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
}
5151
}
5252
ExcludeRules = @(
53+
'PSAvoidUsingWriteHost', # Write-Host is acceptable in guidance scripts.
5354
'PSMissingModuleManifestField', # This rule is not applicable until the module is built.
5455
'PSUseToExportFieldsInManifest'
5556
)

.github/workflows/Docs.yml

Lines changed: 33 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -7,52 +7,47 @@ on:
77
- main
88
paths:
99
- docs/**
10-
- mkdocs.yml
10+
- zensical.toml
1111
- .github/workflows/Docs.yml
1212

13-
env:
14-
GH_TOKEN: ${{ github.token }}
15-
MKDOCS_GIT_COMMITTERS_APIKEY: ${{ github.token }}
16-
17-
defaults:
18-
run:
19-
shell: pwsh
13+
concurrency:
14+
group: ${{ github.workflow }}-${{ github.ref }}
15+
cancel-in-progress: false
2016

2117
permissions:
22-
contents: write # to push GitHub Pages to the gh-pages branch
23-
pages: write # to deploy to Pages
24-
id-token: write # to verify the deployment originates from an appropriate source
18+
contents: read
2519

2620
jobs:
2721
build:
28-
runs-on: ubuntu-latest
22+
name: Build and deploy docs
23+
runs-on: ubuntu-24.04
24+
environment:
25+
name: github-pages
26+
url: ${{ steps.deployment.outputs.page_url }}
27+
permissions:
28+
contents: read
29+
pages: write # deploy to GitHub Pages
30+
id-token: write # OIDC token for actions/deploy-pages
2931
steps:
30-
- uses: actions/checkout@v6
32+
- uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0
33+
34+
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1
3135
with:
32-
fetch-depth: 0
3336
persist-credentials: false
3437

35-
- name: Connect to GitHub
36-
uses: PSModule/GitHub-Script@0097f3bbe3f413f3b577b9bcc600727b0ca3201a # v1.7.10
37-
38-
- name: Install mkdocs-material
39-
env:
40-
GH_TOKEN: ${{ secrets.MATERIAL_FOR_MKDOCS_INSIDER_PAT }}
41-
run: |
42-
pip install git+https://$env:GH_TOKEN@github.com/squidfunk/mkdocs-material-insiders.git
43-
44-
- name: Install plugins
45-
run: |
46-
pip install mkdocs-git-authors-plugin
47-
pip install mkdocs-git-revision-date-localized-plugin
48-
pip install mkdocs-git-committers-plugin-2
49-
pip install mkdocs-rss-plugin
50-
pip install "mkdocs-material[imaging]"
51-
pip install mkdocs-table-reader-plugin
52-
53-
- name: Build mkdocs-material project
54-
run: |
55-
mkdocs build --config-file ./mkdocs.yml --strict --site-dir _site/
56-
57-
- name: Deploy to GitHub Pages
58-
run: mkdocs gh-deploy --force
38+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
39+
with:
40+
python-version: 3.x
41+
42+
- name: Install Zensical
43+
run: pip install zensical
44+
45+
- name: Build Zensical project
46+
run: zensical build --clean
47+
48+
- uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4.0.0
49+
with:
50+
path: site
51+
52+
- uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5
53+
id: deployment

.github/workflows/Linter.yml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: Linter
22

3-
run-name: "Linter - [${{ github.event.pull_request.title }} #${{ github.event.pull_request.number }}] by @${{ github.actor }}"
3+
run-name: 'Linter - [${{ github.event.pull_request.title }} #${{ github.event.pull_request.number }}] by @${{ github.actor }}'
44

55
on: [pull_request]
66

@@ -9,27 +9,29 @@ concurrency:
99
cancel-in-progress: true
1010

1111
permissions:
12-
contents: read
13-
packages: read
14-
statuses: write
12+
contents: read # checkout the repository
13+
packages: read # read packages for dependency review
14+
statuses: write # report linter status checks
1515

1616
jobs:
1717
Lint:
1818
name: Lint code base
1919
runs-on: ubuntu-latest
2020
steps:
2121
- name: Checkout repo
22-
uses: actions/checkout@v6
22+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
2323
with:
2424
fetch-depth: 0
2525
persist-credentials: false
2626

2727
- name: Lint code base
28-
uses: super-linter/super-linter@latest
28+
uses: super-linter/super-linter@9e863354e3ff62e0727d37183162c4a88873df41 # v8.6.0
2929
env:
3030
GITHUB_TOKEN: ${{ github.token }}
31+
VALIDATE_BIOME_LINT: false
3132
VALIDATE_BIOME_FORMAT: false
3233
VALIDATE_JSCPD: false
3334
VALIDATE_JSON_PRETTIER: false
3435
VALIDATE_MARKDOWN_PRETTIER: false
3536
VALIDATE_YAML_PRETTIER: false
37+
VALIDATE_HTML_PRETTIER: false

.github/workflows/Update-Index.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@ jobs:
1414
runs-on: ubuntu-latest
1515
steps:
1616
- name: Checkout repository
17-
uses: actions/checkout@v6
17+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
1818
with:
1919
persist-credentials: false
2020

2121
- name: Update index
2222
uses: PSModule/GitHub-Script@0097f3bbe3f413f3b577b9bcc600727b0ca3201a # v1.7.10
2323
with:
24-
ClientID: ${{ secrets.SCRIBBLER_BOT_CLIENT_ID }}
25-
PrivateKey: ${{ secrets.SCRIBBLER_BOT_PRIVATE_KEY }}
24+
# Org-level shared secrets used across multiple repositories — no dedicated GitHub Environment needed.
25+
ClientID: ${{ secrets.SCRIBBLER_BOT_CLIENT_ID }} # zizmor: ignore[secrets-outside-env]
26+
PrivateKey: ${{ secrets.SCRIBBLER_BOT_PRIVATE_KEY }} # zizmor: ignore[secrets-outside-env]
2627
Script: .github/scripts/Update-Index.ps1

docs/Agents/Git-Worktrees.md

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# Git Worktrees
2+
3+
All repositories are set up as **bare clones with worktrees**. This enables parallel work — multiple agents (or a human and an agent) can work on different issues in the same repository simultaneously without conflicts, stashing, or context-switching.
4+
5+
## Why worktrees
6+
7+
| Problem with traditional clones | How worktrees solve it |
8+
| -------------------------------------------- | --------------------------------------------------------- |
9+
| Only one branch checked out at a time | Each issue gets its own worktree — parallel by default |
10+
| Switching branches requires clean state | Worktrees are independent — no stashing or committing WIP |
11+
| Agent work blocks human work on same repo | Different worktrees, no interference |
12+
| Default branch gets dirty during development | `main/` worktree is always a clean reference |
13+
14+
## Repository layout
15+
16+
```text
17+
<repo-root>/
18+
├── .bare/ # bare git data (the actual repository)
19+
├── .git # file containing: gitdir: ./.bare
20+
├── main/ # worktree: default branch (always clean, never worked in directly)
21+
├── 42-add-pagination/ # worktree: issue #42 in progress
22+
└── 99-fix-null-ref/ # worktree: issue #99 in progress
23+
```
24+
25+
- **`.bare/`** — the shared git object store. All worktrees share this.
26+
- **`.git`** — a file (not a directory) that points git tooling to `.bare/`.
27+
- **`main/`** — the default branch worktree. Kept as a clean reference. Used for diffing, reading docs, running comparisons. Never directly committed to.
28+
- **`<N>-<slug>/`** — one worktree per issue in flight. Named by issue number and a short slug. Branch name matches the folder name.
29+
30+
## Remotes
31+
32+
Every repository has exactly two remotes (or one, if it is not a fork):
33+
34+
| Remote | Points to | Required | Purpose |
35+
| -------------- | ---------------------------- | -------- | ------------------------------------------------ |
36+
| **`origin`** | Our copy on the server | Always | Push branches, open PRs, CI runs against this. |
37+
| **`upstream`** | The parent repo (forks only) | Forks | Track upstream changes, sync the default branch. |
38+
39+
No other remotes are added. This keeps the model simple and predictable for both humans and agents.
40+
41+
### How it works in practice
42+
43+
- **Non-fork repos** — only `origin` exists. Branches are pushed to `origin`, PRs are opened against `origin`.
44+
- **Forked repos**`origin` is our fork, `upstream` is the original repository. The default branch tracks `upstream` for syncing; feature branches are pushed to `origin` and PRs are opened from `origin` into `upstream`.
45+
46+
### Fetch configuration
47+
48+
Both remotes are configured with full refspecs so `git fetch --all --prune` keeps everything current:
49+
50+
```text
51+
[remote "origin"]
52+
fetch = +refs/heads/*:refs/remotes/origin/*
53+
54+
[remote "upstream"] # forks only
55+
fetch = +refs/heads/*:refs/remotes/upstream/*
56+
```
57+
58+
## Setup (one-time per repository)
59+
60+
```powershell
61+
# Clone as bare into .bare/
62+
git clone --bare https://github.com/<owner>/<repo>.git .bare
63+
64+
# Create the .git pointer file
65+
Set-Content .git "gitdir: ./.bare" -NoNewline
66+
67+
# Configure fetch refspec (bare clones don't set this automatically)
68+
git -C .bare config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
69+
70+
# Fetch remote branches
71+
git -C .bare fetch origin
72+
73+
# Create the default branch worktree
74+
git -C .bare worktree add ../main main
75+
```
76+
77+
> The [Checkout-GitHubRepo](https://github.com/MariusStorhaug/.dev/blob/main/.github/Checkout-GitHubRepo.ps1) script automates this for all repositories.
78+
79+
## Working on an issue
80+
81+
```powershell
82+
# From the repo root (where .bare/ lives)
83+
git -C .bare worktree add ../42-add-pagination -b 42-add-pagination main
84+
85+
# Open in VS Code
86+
code 42-add-pagination
87+
```
88+
89+
Then follow the normal Implement flow: initial commit → push → draft PR → build → finalize.
90+
91+
## Cleanup after merge
92+
93+
```powershell
94+
# Remove the worktree
95+
git -C .bare worktree remove 42-add-pagination
96+
97+
# Prune if needed (removes stale worktree references)
98+
git -C .bare worktree prune
99+
```
100+
101+
The sync script handles this automatically — worktrees whose branch no longer exists on any remote are removed during the next sync.
102+
103+
## Parallel agents
104+
105+
The worktree model enables multiple agents to work in the same repository at the same time:
106+
107+
- Each agent operates in its own worktree (its own issue folder).
108+
- No merge conflicts during development — conflicts only surface at PR merge time.
109+
- The default branch worktree provides a stable reference for all agents to read from.
110+
- CI runs independently per PR, so agents don't block each other.
111+
112+
```text
113+
Agent A: working in 42-add-pagination/
114+
Agent B: working in 43-fix-auth-flow/
115+
Human: reviewing in main/ or reading docs
116+
```
117+
118+
## VS Code integration
119+
120+
- **Open the worktree folder directly** — VS Code's Git extension auto-detects the git context.
121+
- **Multi-root workspace** — add multiple worktrees to one window (`File → Add Folder to Workspace`) to reference `main/` while coding in another.
122+
- **Terminal cwd** — ensure the integrated terminal is in the worktree folder, not the bare root.
123+
124+
## Rules
125+
126+
1. **Never commit directly to the default branch worktree.** It exists for reference only.
127+
2. **One worktree per issue.** The folder name matches the branch name: `<N>-<slug>`.
128+
3. **Clean up after merge.** Remove the worktree and let the sync script prune stale branches.
129+
4. **All git config lives in `.bare/`** — it applies to every worktree automatically.
130+
5. **Only `origin` and `upstream` remotes.** No other remotes. `upstream` only exists for forks.

docs/Agents/Issue-Format.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ A clear, imperative-mood statement of the work. Not a question, not a symptom.
3838

3939
The description has three sections separated by horizontal rules (`---`), ordered from behavioural to architectural to tactical. The user need is understood before the technical discussion.
4040

41-
| Section | Owner | Present in |
42-
| ------- | -------------- | ----------------------------------------------------- |
43-
| 1 — Context and Request | Ideator → Clarifier | Every issue at every level (Task, PBI, Epic) |
44-
| 2 — Technical Decisions | Planner | Task always; PBI / Epic for decomposition rationale |
45-
| 3 — Implementation Plan | Planner | Task always (task list); PBI / Epic (links to children) |
41+
| Section | Owner | Present in |
42+
| ------------------------- | --------------------- | ------------------------------------------------------------- |
43+
| 1 — Context and Request | Ideator → Clarifier | Every issue at every level (Task, PBI, Epic) |
44+
| 2 — Technical Decisions | Planner | Task always; PBI / Epic for decomposition rationale |
45+
| 3 — Implementation Plan | Planner | Task always (task list); PBI / Epic (links to children) |
4646

4747
## Section 1 — Context and Request
4848

docs/Agents/Issue-Hierarchy.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ Work in PSModule is tracked at three levels. The level reflects **scope and aggr
44

55
## The three levels
66

7-
| Level | Issue type | Scope | Output |
8-
| ------------------------ | ------------ | -------------------------------------------------- | --------------------------------------------------------- |
9-
| **Task** | `Task` | One deliverable. One small reviewable PR. | Working software. |
10-
| **Product Backlog Item** | `PBI` | A body of work composed of multiple Tasks. | Tracking, delegation, oversight, visibility into progress. |
11-
| **Epic** | `Epic` | Strategic chunk needing multiple PBIs. | The co-planning artifact. Where OKRs become initiatives. |
7+
| Level | Issue type | Scope | Output |
8+
| ------------------------ | ------------ | -------------------------------------------------- | ------------------------------------------------------------------- |
9+
| **Task** | `Task` | One deliverable. One small reviewable PR. | Working software. |
10+
| **Product Backlog Item** | `PBI` | A body of work composed of multiple Tasks. | Tracking, delegation, oversight, visibility into progress. |
11+
| **Epic** | `Epic` | Strategic chunk needing multiple PBIs. | The co-planning artifact. Where OKRs become initiatives. |
1212

1313
> The name **Product Backlog Item** is chosen for its neutral vibe — it works equally well for a feature, a fix, a refactor, or an internal capability. "Feature" implies user-visible value, which isn't always the case for the middle tier.
1414
@@ -76,10 +76,10 @@ Text-level conventions on child issues:
7676

7777
## How the sections differ by level
7878

79-
| Section | Task | PBI | Epic |
80-
| ------------------------ | ----------------------------- | ------------------------------------------------------------------- | -------------------------------------------------------------------- |
81-
| Section 1 (Context/Req) | The deliverable's user story | The grouped goal's user story | The strategic outcome — vision, why, the change in the world |
82-
| Section 2 (Decisions) | Implementation decisions | Decomposition rationale + interface decisions between children | Decomposition rationale + which PBIs and why |
79+
| Section | Task | PBI | Epic |
80+
| ------------------------ | ----------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------- |
81+
| Section 1 (Context/Req) | The deliverable's user story | The grouped goal's user story | The strategic outcome — vision, why, the change in the world |
82+
| Section 2 (Decisions) | Implementation decisions | Decomposition rationale + interface decisions between children | Decomposition rationale + which PBIs and why |
8383
| Section 3 (Plan) | Checkbox task list | Linked list of child issues (Tasks and/or sub-PBIs) | Linked list of child PBIs |
8484

8585
For Epics, Section 1 should explicitly contain the **Golden Circle framing**: Why, How, What. See [Principles → Golden Circle](Principles.md#start-with-why--the-golden-circle).

0 commit comments

Comments
 (0)