rename the project to khosra, initialise the module
Naming is free before a module is published, a URL is shared, or a binary is deployed; every day it waits costs more. Swept every form: module path, binary, cmd/ directory, KHOSRA_SITE, the feature-loop skill directory, and the prose in earlier ADRs — which describe this project under its old name, not a different project. Recorded as ADR-0030. go mod init lands here rather than with the first feature because the module path is what the rename is about. x/text and yaml.v3 are required but not yet imported, so both are indirect and no direct dependency is claimed yet.
This commit is contained in:
@@ -19,6 +19,8 @@
|
||||
"Bash(git diff:*)",
|
||||
"Bash(git log:*)",
|
||||
"Bash(git show:*)",
|
||||
"Bash(git add:*)",
|
||||
"Bash(git commit:*)",
|
||||
"Bash(rg:*)",
|
||||
"Bash(wc:*)",
|
||||
"Bash(curl -s http://localhost:*)",
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/atelier
|
||||
/khosra
|
||||
*.test
|
||||
*.out
|
||||
.DS_Store
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# atelier — agent constitution
|
||||
# khosra — agent constitution
|
||||
|
||||
`atelier` is a flat-file personal publishing engine in Go, built solo, one feature at a time.
|
||||
`khosra` is a flat-file personal publishing engine in Go, built solo, one feature at a time.
|
||||
You implement; the human owns scope and taste. This file overrides your defaults.
|
||||
|
||||
A **personal publishing substrate**: a directory of Markdown becomes an owned, networked home for
|
||||
@@ -74,7 +74,7 @@ service or a core-model change): stop, say so in a paragraph, propose the leaf,
|
||||
## 4. The loop (every request, no exceptions)
|
||||
|
||||
`Clarify → Plan → Implement → Verify → Document → Report`.
|
||||
Procedure: `.claude/skills/atelier-feature-loop/SKILL.md`. The two gates people skip:
|
||||
Procedure: `.claude/skills/khosra-feature-loop/SKILL.md`. The two gates people skip:
|
||||
|
||||
**Clarify.** Only questions whose answer changes the code or the bytes on disk. Max three,
|
||||
batched, up front, each with a **bold** default so silence answers. Never about naming, formatting,
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
# The atelier harness — human's guide
|
||||
# The khosra harness — human's guide
|
||||
|
||||
Scaffolding that makes an agent build `atelier` the way you want: minimally, surgically, questions
|
||||
Scaffolding that makes an agent build `khosra` the way you want: minimally, surgically, questions
|
||||
before code, docs that stay true.
|
||||
|
||||
`README.md` is a two-line signpost — human here, agent to `CLAUDE.md`. `CLAUDE.md` is the
|
||||
@@ -107,7 +107,7 @@ imports `cmd`. One convenient sibling import is what turns a layered engine into
|
||||
it always looks locally reasonable — so it is a hard failure, not a review note.
|
||||
|
||||
**Feature locality is enforced, not hoped for.** A feature is one directory under `internal/ext/<name>/`
|
||||
plus one line in `cmd/atelier/wire.go`. `verify.sh` fails on a feature importing a sibling and on a
|
||||
plus one line in `cmd/khosra/wire.go`. `verify.sh` fails on a feature importing a sibling and on a
|
||||
feature package without a `doc.go` — the first because sibling imports make an agent's read set compound,
|
||||
the second because a four-line `doc.go` turns orientation into a fifteen-line read (ADR-0027).
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# atelier
|
||||
# khosra
|
||||
|
||||
A flat-file personal publishing engine in Go. Point the binary at a directory of Markdown and it
|
||||
becomes an owned, networked home for fiction, webcomics, art, and essays, in English and Bengali.
|
||||
|
||||
@@ -12,7 +12,7 @@ whatever builds it. What exists is `state.md`'s job. Never build a `[spec]` sect
|
||||
|
||||
## The site root
|
||||
|
||||
The engine is pointed at a site root outside this repository (`-site <dir>`, or `ATELIER_SITE`), with
|
||||
The engine is pointed at a site root outside this repository (`-site <dir>`, or `KHOSRA_SITE`), with
|
||||
its own git history (ADR-0011). Nothing in the engine repo is content. `templates/` in the site root
|
||||
overrides the defaults the binary embeds, so a bare root still renders.
|
||||
|
||||
|
||||
+3
-3
@@ -8,7 +8,7 @@ goes through an ADR, not a diff.
|
||||
- `net/http`, `html/template`, `log/slog`, `os`, `io/fs`, `embed`. Routing is `http.ServeMux` with Go
|
||||
1.22+ patterns — `GET /{section}/{slug}/` and `{path...}` for multi-segment slugs — so no router
|
||||
library is needed. No web framework, ORM, or config library — flags plus environment variables, parsed in one place. The site root
|
||||
(`-site`, `ATELIER_SITE`) is the only required setting; default templates are `embed`ded so a bare
|
||||
(`-site`, `KHOSRA_SITE`) is the only required setting; default templates are `embed`ded so a bare
|
||||
site root renders (ADR-0011).
|
||||
- New dependency = ADR + human approval + `scripts/allowed-deps.txt`. `verify.sh` enforces it.
|
||||
- Prefer 40 lines of obvious code over a dependency doing it in one call — unless the 40 lines would be
|
||||
@@ -16,7 +16,7 @@ goes through an ADR, not a diff.
|
||||
|
||||
## Package layout
|
||||
```
|
||||
cmd/atelier/ main, flag parsing, explicit wiring — the only place things are assembled
|
||||
cmd/khosra/ main, flag parsing, explicit wiring — the only place things are assembled
|
||||
internal/content/ bundles, frontmatter, slugs, queries — knows the disk, not HTTP
|
||||
internal/render/ markdown, transforms, templates — knows content, not HTTP
|
||||
internal/web/ handlers, routing, headers, caching — knows both, exposes neither
|
||||
@@ -26,7 +26,7 @@ Dependencies point inward. `internal/content` imports nothing from the others; `
|
||||
and is imported by nothing. A feature under `internal/ext/` may import `internal/content` and
|
||||
`internal/render`, and must not import `internal/web`, `cmd/`, or **another feature** — sibling imports
|
||||
are what make an agent's read set compound (ADR-0027). Every `internal/ext/*` package carries a `doc.go`;
|
||||
`verify.sh` fails without one. Routes reach `web` by assembly in `cmd/atelier/wire.go`, so `web` never
|
||||
`verify.sh` fails without one. Routes reach `web` by assembly in `cmd/khosra/wire.go`, so `web` never
|
||||
learns features exist. No `utils`, `helpers`, `common`, `shared`, `manager`, `base`,
|
||||
`impl`, `core` — a package name not describing a domain is a smell. Flat until a package exceeds
|
||||
`FILE_LOC_WARN`; do not pre-partition, and a single-file package therefore warns at the same point it
|
||||
|
||||
+43
-2
@@ -116,7 +116,7 @@ Revisit if: the engine can no longer boot and serve correctly with every externa
|
||||
Date: 2026-07-28 · Status: accepted
|
||||
Decision: the engine is pointed at a **site root** — a directory outside this repository, versioned in
|
||||
its own git repo — holding `content/`, `static/`, and optionally `templates/` overriding the defaults
|
||||
the binary embeds. Selected by `-site <dir>` or `ATELIER_SITE`. This repository contains engine source
|
||||
the binary embeds. Selected by `-site <dir>` or `KHOSRA_SITE`. This repository contains engine source
|
||||
only; no content, ever, not even an example.
|
||||
Why: content is the database, and a database does not live in the application's repo. Mixing them
|
||||
interleaves "fixed a typo in a poem" with "extracted the resolver" in one history, makes every typo a
|
||||
@@ -298,7 +298,7 @@ Revisit if: it starts accumulating design decisions — then split it into a ref
|
||||
## ADR-0027 — Feature locality: one directory, no sibling imports, a mandatory `doc.go`
|
||||
Date: 2026-07-30 · Status: accepted
|
||||
Decision: a feature is one directory under `internal/ext/<name>/` from its first use, plus one line in
|
||||
`cmd/atelier/wire.go` — the only file that knows every feature. No `internal/ext` package may import
|
||||
`cmd/khosra/wire.go` — the only file that knows every feature. No `internal/ext` package may import
|
||||
another. Every one carries a `doc.go` stating, in four lines: what it contributes, which cascade keys it
|
||||
reads, which theme-contract fields it adds, and what it deliberately does not do. A feature may import
|
||||
`internal/content` and `internal/render`; never `internal/web`, never `cmd/`, never a sibling.
|
||||
@@ -313,3 +313,44 @@ inward (earning it under the counters) or stay duplicated until the third use, w
|
||||
rather than a new one. Expensive — `wire.go` absorbs all the coupling on purpose and will look
|
||||
repetitive; and this buys cheap *features*, not cheap spine changes, which still need the core read.
|
||||
Revisit if: `wire.go` becomes hard to read, which means the registry from `extensions.md` is due.
|
||||
|
||||
## ADR-0028 — Pagination lives in the path: `/{section}/page/2/`
|
||||
Date: 2026-07-30 · Status: accepted
|
||||
Decision: page two of a listing is `/{section}/page/2/`; page one is the bare listing URL and never
|
||||
`/page/1/`, which permanently redirects to it. Tag listings compose the same way:
|
||||
`/tags/{tag}/page/2/`. `page` is therefore a reserved segment inside a section.
|
||||
Why: a query parameter is not a permalink — it reads as ephemeral, is dropped by careless sharing, and
|
||||
splits caching by URL shape rather than by content. Putting it in the path keeps every listing page
|
||||
linkable and cacheable on the same terms as a bundle.
|
||||
Consequence: cheap — one more resolver case, and every paginated listing is a first-class URL. Expensive
|
||||
— no bundle may be slugged `page` inside a paginated section, and changing the page size renumbers pages,
|
||||
so page URLs are stable only while the size is.
|
||||
Revisit if: never for the shape. Page size is a separate setting and changing it is a URL event.
|
||||
|
||||
## ADR-0029 — A bundle that fails to parse is skipped loudly, not fatal
|
||||
Date: 2026-07-30 · Status: accepted
|
||||
Decision: a bundle whose frontmatter or filename cannot be parsed is logged at error level with its path
|
||||
and line, excluded from the site, and does not stop startup or any request. The `check` command reports
|
||||
the same failures as errors, and that is where a non-zero exit belongs.
|
||||
Why: `conventions.md` says startup failure is fatal and loud, and separately that request-time failure
|
||||
degrades. A single mistyped colon in one post is not a startup failure — treating it as one means one
|
||||
typo takes the whole site down, which is the worst possible failure mode for a personal site published
|
||||
from a text editor. Fatal is right for a broken site root or an unreadable directory, not for one file.
|
||||
Consequence: cheap — the site always serves whatever is valid, and the author sees the error in the log
|
||||
and in `check`. Expensive — a silently absent page is a real failure mode, so the log line must name the
|
||||
file and the reason plainly, and `check` must exist early enough to be the place you look.
|
||||
Revisit if: skipped bundles start going unnoticed in practice — then `check` runs in CI, rather than the
|
||||
engine becoming fatal.
|
||||
|
||||
## ADR-0030 — The project is named khosra
|
||||
Date: 2026-07-30 · Status: accepted
|
||||
Decision: the engine is `khosra`. Module path `khosra`, binary `khosra`, command directory
|
||||
`cmd/khosra/`, environment variable `KHOSRA_SITE`, feature-loop skill `khosra-feature-loop`. The former
|
||||
name `atelier` appears nowhere, including in earlier ADRs, which describe this project under its old
|
||||
name rather than a different project.
|
||||
Why: naming is the author's, and it is free now — before a module is published, a URL is shared, or a
|
||||
binary is deployed. Every day it waits, it costs more.
|
||||
Consequence: cheap now, and permanent-ish once the module path is fetched by anything. Expensive later —
|
||||
a module rename after publication needs a redirect or a major-version bump, and a deployed binary name
|
||||
appears in service files and container tags.
|
||||
Revisit if: never. Renaming again costs strictly more than this did.
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ type Extension struct {
|
||||
}
|
||||
```
|
||||
|
||||
`cmd/atelier/wire.go` holds the only list of enabled extensions. Enabling or disabling one is a
|
||||
`cmd/khosra/wire.go` holds the only list of enabled extensions. Enabling or disabling one is a
|
||||
one-line diff and a rebuild. Removing one leaves no trace elsewhere — that property is the test of
|
||||
whether the contract is right.
|
||||
|
||||
|
||||
+6
-2
@@ -5,8 +5,12 @@ If this file disagrees with the code, the code is right and this file is a bug.
|
||||
|
||||
## Inventory
|
||||
|
||||
No Go source, no `go.mod`. The harness is installed; the engine is unwritten. This repo holds engine
|
||||
source only — the site root is external and passed with `-site` (ADR-0011).
|
||||
| File | Purpose | LOC |
|
||||
|---|---|---|
|
||||
| `go.mod` | module `khosra`; `x/text` and `yaml.v3` required, not yet imported | 8 |
|
||||
|
||||
No Go source yet. This repo holds engine source only — the site root is external and passed with `-site`
|
||||
(ADR-0011).
|
||||
|
||||
Dependencies: none.
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
module khosra
|
||||
|
||||
go 1.26.1
|
||||
|
||||
require (
|
||||
golang.org/x/text v0.40.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
@@ -0,0 +1,5 @@
|
||||
golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
|
||||
golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
+1
-1
@@ -333,7 +333,7 @@ longfuncs=$(echo "$gofiles" | xargs awk -v m="$FUNC_LOC_WARN" '
|
||||
if [ -f Dockerfile ] && [ "${VERIFY_DOCKER:-0}" = "1" ]; then
|
||||
head_ "container (VERIFY_DOCKER=1)"
|
||||
if command -v docker >/dev/null 2>&1; then
|
||||
if docker build -q -t atelier:verify . >/tmp/docker.log 2>&1; then
|
||||
if docker build -q -t khosra:verify . >/tmp/docker.log 2>&1; then
|
||||
pass "docker build"
|
||||
else
|
||||
bad "docker build"; tail -20 /tmp/docker.log | sed 's/^/ /'
|
||||
|
||||
Reference in New Issue
Block a user