Compare commits
25 Commits
f43445caea
...
llm-prose-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cedf98b83e | ||
|
|
368fc0edf0 | ||
|
|
3fcc1750ff | ||
|
|
45b379011d | ||
| 58d564b641 | |||
| a1052b758f | |||
|
|
a2dd953601 | ||
|
|
f921dee839 | ||
| a1ffb1591b | |||
|
|
699f97d093 | ||
| 1955922857 | |||
|
|
a8cf966df6 | ||
|
|
dcb6ca4339 | ||
| dda0d01faa | |||
|
|
7676ec16c3 | ||
|
|
f9dcef4c9e | ||
| 189e54862e | |||
| 05fe766c62 | |||
| cb5d630158 | |||
| b5575b9f59 | |||
| e97b48eea4 | |||
| 3768b8ca02 | |||
| 03bf0b8445 | |||
| 3a5ac2d72f | |||
| 00c21cc5c5 |
32
.golangci.yml
Normal file
32
.golangci.yml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
version: "2"
|
||||||
|
|
||||||
|
run:
|
||||||
|
timeout: 5m
|
||||||
|
modules-download-mode: readonly
|
||||||
|
|
||||||
|
linters:
|
||||||
|
default: all
|
||||||
|
disable:
|
||||||
|
# Genuinely incompatible with project patterns
|
||||||
|
- exhaustruct # Requires all struct fields
|
||||||
|
- depguard # Dependency allow/block lists
|
||||||
|
- godot # Requires comments to end with periods
|
||||||
|
- wsl # Deprecated, replaced by wsl_v5
|
||||||
|
- wrapcheck # Too verbose for internal packages
|
||||||
|
- varnamelen # Short names like db, id are idiomatic Go
|
||||||
|
|
||||||
|
linters-settings:
|
||||||
|
lll:
|
||||||
|
line-length: 88
|
||||||
|
funlen:
|
||||||
|
lines: 80
|
||||||
|
statements: 50
|
||||||
|
cyclop:
|
||||||
|
max-complexity: 15
|
||||||
|
dupl:
|
||||||
|
threshold: 100
|
||||||
|
|
||||||
|
issues:
|
||||||
|
exclude-use-default: false
|
||||||
|
max-issues-per-linter: 0
|
||||||
|
max-same-issues: 0
|
||||||
2
Makefile
2
Makefile
@@ -1,5 +1,7 @@
|
|||||||
.PHONY: test lint fmt fmt-check check docker hooks
|
.PHONY: test lint fmt fmt-check check docker hooks
|
||||||
|
|
||||||
|
# flags are repeated here (also in .prettierrc) so this Makefile works
|
||||||
|
# standalone when copied as a template
|
||||||
PRETTIER := yarn run prettier
|
PRETTIER := yarn run prettier
|
||||||
|
|
||||||
test:
|
test:
|
||||||
|
|||||||
116
README.md
116
README.md
@@ -6,16 +6,90 @@ useful prompts for working with large language models.
|
|||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
Bring an existing repo up to standards (run from within the repo):
|
### Existing Repo
|
||||||
|
|
||||||
|
Run from within the repo you want to bring up to standards. Clone the prompts
|
||||||
|
repo once, then run both commands in order.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
P=$(mktemp -d) && git clone --depth 1 https://git.eeqj.de/sneak/prompts.git "$P" && claude "Read $P/prompts/REPO_POLICIES.md and $P/prompts/EXISTING_REPO_CHECKLIST.md, then bring this repo up to those standards."
|
export TD="$(mktemp -d)"
|
||||||
|
git clone --depth 1 https://git.eeqj.de/sneak/prompts.git "$TD"
|
||||||
```
|
```
|
||||||
|
|
||||||
Start a new repo from scratch:
|
**Repository structure and policies:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
P=$(mktemp -d) && git clone --depth 1 https://git.eeqj.de/sneak/prompts.git "$P" && claude "Read $P/prompts/REPO_POLICIES.md and $P/prompts/NEW_REPO_CHECKLIST.md, then set up this new repo according to those standards."
|
claude "Read $TD/prompts/REPO_POLICIES.md and
|
||||||
|
$TD/prompts/EXISTING_REPO_CHECKLIST.md, then bring this repo up to those
|
||||||
|
standards. Your scope is repo scaffolding and policy compliance:
|
||||||
|
Makefile, Dockerfile, .dockerignore, .gitignore, .editorconfig, CI
|
||||||
|
workflow, README sections, LICENSE, REPO_POLICIES.md, and any
|
||||||
|
language-specific config files (.golangci.yml, .prettierrc, etc.).
|
||||||
|
You must also run the formatter (make fmt) and fix any linter errors
|
||||||
|
(make lint) so that make check passes — this will touch source code,
|
||||||
|
but do not restructure, refactor, or rewrite any application logic.
|
||||||
|
Follow the policies yourself: work on a feature branch, never git add -A,
|
||||||
|
and make each logical change a separate commit (e.g. one commit for
|
||||||
|
formatting, one for linter fixes, one for README updates, one for each
|
||||||
|
new repo file added, etc.)."
|
||||||
|
```
|
||||||
|
|
||||||
|
**Code style and conventions:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude "Read $TD/prompts/CODE_STYLEGUIDE.md and whichever
|
||||||
|
language-specific styleguides in $TD/prompts/ apply to this repo
|
||||||
|
(CODE_STYLEGUIDE_GO.md, CODE_STYLEGUIDE_JS.md, CODE_STYLEGUIDE_PYTHON.md,
|
||||||
|
GO_HTTP_SERVER_CONVENTIONS.md). Then review the application code in this
|
||||||
|
repo and bring it into compliance with those coding standards. Your scope
|
||||||
|
is application code structure and style: naming, patterns, error
|
||||||
|
handling, project layout, and conventions described in the styleguides.
|
||||||
|
Do not modify repo scaffolding (Makefile, Dockerfile, CI workflow,
|
||||||
|
.gitignore, .editorconfig, etc.) — only application code. Work on a
|
||||||
|
feature branch, never git add -A, and make each logical change a
|
||||||
|
separate commit."
|
||||||
|
```
|
||||||
|
|
||||||
|
### New Repo
|
||||||
|
|
||||||
|
Run from inside the directory where you want to create a new repo. Clone the
|
||||||
|
prompts repo once, then run both commands in order.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export TD="$(mktemp -d)"
|
||||||
|
git clone --depth 1 https://git.eeqj.de/sneak/prompts.git "$TD"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Repository scaffolding:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude "Read $TD/prompts/REPO_POLICIES.md and
|
||||||
|
$TD/prompts/NEW_REPO_CHECKLIST.md, then set up this new repo according
|
||||||
|
to those standards. Your scope is repo structure and required files:
|
||||||
|
README.md, LICENSE, REPO_POLICIES.md, Makefile, Dockerfile, .dockerignore,
|
||||||
|
.gitignore, .editorconfig, CI workflow, and language-specific config.
|
||||||
|
Run the formatter (make fmt) and fix any linter errors (make lint) so
|
||||||
|
that make check passes — this will touch source code, but do not
|
||||||
|
restructure, refactor, or rewrite any application logic. Follow the
|
||||||
|
policies yourself: work on a feature branch, never git add -A, and make
|
||||||
|
each logical change a separate commit (e.g. one commit for formatting,
|
||||||
|
one for linter fixes, one for README, one for each new repo file, etc.)."
|
||||||
|
```
|
||||||
|
|
||||||
|
**Code style and conventions:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude "Read $TD/prompts/CODE_STYLEGUIDE.md and whichever
|
||||||
|
language-specific styleguides in $TD/prompts/ apply to this repo
|
||||||
|
(CODE_STYLEGUIDE_GO.md, CODE_STYLEGUIDE_JS.md, CODE_STYLEGUIDE_PYTHON.md,
|
||||||
|
GO_HTTP_SERVER_CONVENTIONS.md). Then review the application code in this
|
||||||
|
repo and bring it into compliance with those coding standards. Your scope
|
||||||
|
is application code structure and style: naming, patterns, error
|
||||||
|
handling, project layout, and conventions described in the styleguides.
|
||||||
|
Do not modify repo scaffolding (Makefile, Dockerfile, CI workflow,
|
||||||
|
.gitignore, .editorconfig, etc.) — only application code. Work on a
|
||||||
|
feature branch, never git add -A, and make each logical change a
|
||||||
|
separate commit."
|
||||||
```
|
```
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
@@ -36,15 +110,39 @@ share, and evolve prompts across projects.
|
|||||||
|
|
||||||
## Design
|
## Design
|
||||||
|
|
||||||
The repository is a flat collection of Markdown files. Each file contains one or
|
The repository is a collection of Markdown files organized in the `prompts/`
|
||||||
more related prompts or policy documents. There is no build step or runtime
|
subdirectory. Each file contains one or more related prompts or policy
|
||||||
component; the prompts are consumed by copying them into other projects or
|
documents. There is no build step or runtime component; the prompts are consumed
|
||||||
referencing them directly.
|
by copying them into other projects or referencing them directly.
|
||||||
|
|
||||||
|
## Template Repos
|
||||||
|
|
||||||
|
These template repositories implement the policies defined in this repo and
|
||||||
|
serve as starting points for new projects. They must be kept in sync when
|
||||||
|
policies change.
|
||||||
|
|
||||||
|
- **[template-app-go](https://git.eeqj.de/sneak/template-app-go)** — Go HTTP
|
||||||
|
server template (Uber fx, chi, SQLite, session auth, Prometheus metrics)
|
||||||
|
- **[template-app-js](https://git.eeqj.de/sneak/template-app-js)** — JavaScript
|
||||||
|
SPA template (Vite, Tailwind CSS v4, nginx Docker deployment)
|
||||||
|
- **[template-app-python](https://git.eeqj.de/sneak/template-app-python)** —
|
||||||
|
Python web application template (FastAPI, uvicorn, pytest, black, ruff)
|
||||||
|
|
||||||
|
When updating policies in this repo, also update the template repos to match
|
||||||
|
(Makefile targets, Dockerfile conventions, CI workflows, required files, etc.).
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- **[clawpub](https://git.eeqj.de/sneak/clawpub)** — Real-world examples,
|
||||||
|
rationale, and operational lessons from applying these policies with an
|
||||||
|
[OpenClaw](https://github.com/openclaw/openclaw) AI agent. Includes detailed
|
||||||
|
documentation on how the interlocking check system (CI → Docker → Makefile →
|
||||||
|
tests/lint/fmt) works in practice, why checklists complement prose policies,
|
||||||
|
and failure stories from production use.
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
- Add more prompt templates for common development tasks
|
- Add more prompt templates for common development tasks
|
||||||
- Add CI to lint Markdown
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
1
REPO_POLICIES.md
Symbolic link
1
REPO_POLICIES.md
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
prompts/REPO_POLICIES.md
|
||||||
@@ -1,28 +1,13 @@
|
|||||||
# sneak/styleguide
|
---
|
||||||
|
title: Code Styleguide
|
||||||
|
last_modified: 2026-02-22
|
||||||
|
---
|
||||||
|
|
||||||
The following is the first released version of my personal code styleguide.
|
# All
|
||||||
There are many like it, but this one is mine.
|
|
||||||
|
|
||||||
Only the Go portion is "complete". The others are mostly just placeholders.
|
1. Every repo must have a `Makefile` and a `Dockerfile`. See
|
||||||
|
[Repository Policies](https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/REPO_POLICIES.md)
|
||||||
Feedback and suggestions are not only welcome but explicitly encouraged.
|
for required targets and conventions.
|
||||||
|
|
||||||
[sneak@sneak.berlin](mailto:sneak@sneak.berlin)
|
|
||||||
|
|
||||||
# My 2024 Code Styleguide
|
|
||||||
|
|
||||||
## All
|
|
||||||
|
|
||||||
1. Every project/repo should have a `Makefile` in the root. At a minimum,
|
|
||||||
`make clean`, `make run`, `make fmt`, and `make test` should work. Choose a
|
|
||||||
sane default target (`test` for libraries, `run` or `publish` for binaries).
|
|
||||||
`fmt` should invoke the appropriate formatters for the files in the repo,
|
|
||||||
such as `go fmt`, `prettier`, `black`, etc. Other standard `Makefile` targets
|
|
||||||
include `deploy`, `lint`. Consider the `Makefile` the official documentation
|
|
||||||
about how to operate the repository.
|
|
||||||
|
|
||||||
1. If it's possible to write a `Dockerfile`, include at least a simple one. It
|
|
||||||
should be possible to build and run the project with `docker build .`.
|
|
||||||
|
|
||||||
1. For F/OSS-licensed software, try to include the full source code of the
|
1. For F/OSS-licensed software, try to include the full source code of the
|
||||||
current version (and any dependencies, such as vendored dependencies) in the
|
current version (and any dependencies, such as vendored dependencies) in the
|
||||||
@@ -51,18 +36,16 @@ Feedback and suggestions are not only welcome but explicitly encouraged.
|
|||||||
be enabled in prod.
|
be enabled in prod.
|
||||||
|
|
||||||
1. For services/servers, make a healthcheck available at
|
1. For services/servers, make a healthcheck available at
|
||||||
`/.well-known/healthcheck`. This is out of spec but it is my personal
|
`/.well-known/healthcheck`. The response must have a
|
||||||
standard. This should return a 200 OK if the service is healthy, along with a
|
`Content-Type: application/json` header and return a JSON object containing
|
||||||
JSON object containing the service's name, uptime, and any other relevant
|
the service's name, uptime, and a key of `"status"` with a value of `"ok"`.
|
||||||
information, and a key of "status" with a value of "ok" if the service is
|
Return a 200 for healthy, 5xx for unhealthy.
|
||||||
healthy. Make sure that in the event of a failure, the service returns a 5xx
|
|
||||||
status code for that route.
|
|
||||||
|
|
||||||
1. If possible, for services/servers, include a /metrics endpoint that returns
|
1. If possible, for services/servers, include a /metrics endpoint that returns
|
||||||
Prometheus-formatted metrics. This is not required for all services, but is a
|
Prometheus-formatted metrics. This is not required for all services, but is a
|
||||||
nice-to-have.
|
nice-to-have.
|
||||||
|
|
||||||
## Bash / Shell
|
# Bash / Shell
|
||||||
|
|
||||||
1. Use `[[` instead of `[` for conditionals. It's a shell builtin and doesn't
|
1. Use `[[` instead of `[` for conditionals. It's a shell builtin and doesn't
|
||||||
have to execute a separate process.
|
have to execute a separate process.
|
||||||
@@ -82,7 +65,7 @@ Feedback and suggestions are not only welcome but explicitly encouraged.
|
|||||||
1. Put all code in functions, even a main function. Define all functions then
|
1. Put all code in functions, even a main function. Define all functions then
|
||||||
call main at the bottom of the file.
|
call main at the bottom of the file.
|
||||||
|
|
||||||
## Docker Containers (for services)
|
# Docker Containers (for services)
|
||||||
|
|
||||||
1. Use `runit` with `runsvinit` as the entrypoint for all containers. This
|
1. Use `runit` with `runsvinit` as the entrypoint for all containers. This
|
||||||
allows for easy service management and logging. In startup scripts
|
allows for easy service management and logging. In startup scripts
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
# Golang
|
---
|
||||||
|
title: Code Styleguide — Go
|
||||||
|
last_modified: 2026-02-22
|
||||||
|
---
|
||||||
|
|
||||||
1. Try to hard wrap long lines at 77 characters or less.
|
1. Try to hard wrap long lines at 77 characters or less.
|
||||||
|
|
||||||
@@ -68,11 +71,8 @@
|
|||||||
1. Avoid obvious footguns. For example, use range instead of for loops for
|
1. Avoid obvious footguns. For example, use range instead of for loops for
|
||||||
iterating.
|
iterating.
|
||||||
|
|
||||||
1. Try to use zerolog for logging. It's fast and has a nice API. For
|
1. Use `log/slog` for structured logging. Import `sneak.berlin/go/simplelog`
|
||||||
smaller/quick projects, the standard library's `log` package (and
|
for sensible defaults. Example:
|
||||||
specifically `log/slog`) is fine. In that case, log structured logs whenever
|
|
||||||
possible, and import `sneak.berlin/go/simplelog` to configure it
|
|
||||||
appropriately. Example:
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -105,9 +105,9 @@
|
|||||||
able-to-be-compiled state, linted, and any tests run. The Docker build
|
able-to-be-compiled state, linted, and any tests run. The Docker build
|
||||||
should fail if linting doesn't pass.
|
should fail if linting doesn't pass.
|
||||||
|
|
||||||
1. Include a `Makefile` with targets for at least `clean` and `test`. If there
|
1. Every repo must have a `Makefile`. See
|
||||||
are multiple binaries, include a target for each binary. If there are
|
[Repository Policies](https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/REPO_POLICIES.md)
|
||||||
multiple binaries, include a target for `all` that builds all binaries.
|
for required targets and conventions.
|
||||||
|
|
||||||
1. If you are writing a single-module library, `.go` files are okay in the repo
|
1. If you are writing a single-module library, `.go` files are okay in the repo
|
||||||
root.
|
root.
|
||||||
@@ -130,7 +130,7 @@
|
|||||||
single-file scripts.
|
single-file scripts.
|
||||||
|
|
||||||
1. HTTP HandleFuncs should be returned from methods or functions that need to
|
1. HTTP HandleFuncs should be returned from methods or functions that need to
|
||||||
handle HTTP requests. Don't use methods or our top level functions as
|
handle HTTP requests. Don't use methods or your top level functions as
|
||||||
handlers.
|
handlers.
|
||||||
|
|
||||||
1. Provide a .gitignore file that ignores at least `*.log`, `*.out`, and
|
1. Provide a .gitignore file that ignores at least `*.log`, `*.out`, and
|
||||||
@@ -229,6 +229,29 @@
|
|||||||
|
|
||||||
1. Define your struct types near their constructors.
|
1. Define your struct types near their constructors.
|
||||||
|
|
||||||
|
1. Do not create packages whose sole purpose is to hold type definitions.
|
||||||
|
Packages named `types`, `domain`, or `models` that contain only structs and
|
||||||
|
interfaces (with no behavior) are a code smell. Define types alongside the
|
||||||
|
code that uses them. Type-only packages force consuming packages into alias
|
||||||
|
imports and circular-dependency gymnastics, and indicate that the package
|
||||||
|
boundaries were drawn around nouns instead of responsibilities. If multiple
|
||||||
|
packages need the same type, put it in the package that owns the behavior,
|
||||||
|
or in a small, focused interface package — not in a grab-bag types package.
|
||||||
|
|
||||||
|
1. When defining custom string-based types (e.g. `type ImageID string`),
|
||||||
|
implement `fmt.Stringer`. Use `.String()` at SDK and library boundaries
|
||||||
|
instead of `string(v)`. This makes type conversions explicit, grep-able, and
|
||||||
|
consistent across the codebase. Example:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type ContainerID string
|
||||||
|
|
||||||
|
func (id ContainerID) String() string { return string(id) }
|
||||||
|
|
||||||
|
// At the Docker SDK boundary:
|
||||||
|
resp, err := c.docker.ContainerStart(ctx, id.String(), opts)
|
||||||
|
```
|
||||||
|
|
||||||
1. Define your interface types near the functions that use them, or if you have
|
1. Define your interface types near the functions that use them, or if you have
|
||||||
multiple conformant types, put the interface(s) in their own file.
|
multiple conformant types, put the interface(s) in their own file.
|
||||||
|
|
||||||
@@ -429,7 +452,7 @@
|
|||||||
releasable". "Releasable" in this context means that it builds and functions
|
releasable". "Releasable" in this context means that it builds and functions
|
||||||
as expected, and that all tests and linting passes.
|
as expected, and that all tests and linting passes.
|
||||||
|
|
||||||
## Other Golang Tips and Best Practices (Optional)
|
# Other Golang Tips and Best Practices (Optional)
|
||||||
|
|
||||||
1. For any internet-facing http server, set appropriate timeouts and limits to
|
1. For any internet-facing http server, set appropriate timeouts and limits to
|
||||||
protect against slowloris attacks or huge uploads that can consume server
|
protect against slowloris attacks or huge uploads that can consume server
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
# JavaScript / ECMAScript / ES6
|
---
|
||||||
|
title: Code Styleguide — JavaScript
|
||||||
|
last_modified: 2026-02-22
|
||||||
|
---
|
||||||
|
|
||||||
1. Use `const` for everything. If you need to reassign, use `let`. Never use
|
1. Use `const` for everything. If you need to reassign, use `let`. Never use
|
||||||
`var`.
|
`var`.
|
||||||
@@ -9,9 +12,12 @@
|
|||||||
|
|
||||||
1. Use `prettier` for code formatting, with four spaces for indentation.
|
1. Use `prettier` for code formatting, with four spaces for indentation.
|
||||||
|
|
||||||
1. At a minimum, `npm run test` and `npm run build` should work (complete the
|
1. At a minimum, both `yarn run test`/`yarn run build` and
|
||||||
appropriate scripts in `package.json`). The `Makefile` should call these, do
|
`npm run test`/`npm run build` should work (complete the appropriate scripts
|
||||||
not duplicate the scripts in the `Makefile`.
|
in `package.json`). However, prefer `make test` and `make build` instead —
|
||||||
|
the Makefile is authoritative on how to interact with the repo. See
|
||||||
|
[Repository Policies](https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/REPO_POLICIES.md)
|
||||||
|
for details.
|
||||||
|
|
||||||
# Author
|
# Author
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
# Python
|
---
|
||||||
|
title: Code Styleguide — Python
|
||||||
|
last_modified: 2026-02-22
|
||||||
|
---
|
||||||
|
|
||||||
1. Format all code with `black`, with four space indents.
|
1. Format all code with `black`, with four space indents.
|
||||||
|
|
||||||
2. Put all code in functions. If you are writing a script, put the script in a
|
1. Put all code in functions. If you are writing a script, put the script in a
|
||||||
function called `main` and call `main()` at the end of the script using the
|
function called `main` and call `main()` at the end of the script using the
|
||||||
standard invocation:
|
standard invocation:
|
||||||
|
|
||||||
|
|||||||
@@ -1,56 +1,69 @@
|
|||||||
# Existing Repo Checklist
|
---
|
||||||
|
title: Existing Repo Checklist
|
||||||
|
last_modified: 2026-02-22
|
||||||
|
---
|
||||||
|
|
||||||
Use this checklist when beginning work in a repo that may not yet conform to our
|
Use this checklist when beginning work in a repo that may not yet conform to our
|
||||||
[development policies](https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/REPO_POLICIES.md).
|
repository policies
|
||||||
|
(`https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/REPO_POLICIES.md`).
|
||||||
|
|
||||||
Work on a feature branch. Check each item and fix any gaps before proceeding
|
Work on a feature branch. Check each item and fix any gaps before proceeding
|
||||||
with your task.
|
with your task.
|
||||||
|
|
||||||
## Formatting (do this first)
|
# Formatting (do this first)
|
||||||
|
|
||||||
- [ ] If the repo has never been formatted to our standards, run `make fmt` and
|
- [ ] If the repo has never been formatted to our standards, run `make fmt` and
|
||||||
commit the result as a standalone branch/commit/PR before any other
|
commit the result as a standalone branch/commit/PR before any other
|
||||||
changes. Formatting diffs can be large and should not be mixed with
|
changes. Formatting diffs can be large and should not be mixed with
|
||||||
functional changes.
|
functional changes.
|
||||||
|
|
||||||
## Required Files
|
# Required Files
|
||||||
|
|
||||||
- [ ] `README.md` exists with all required sections (Description, Getting
|
- [ ] `README.md` exists with all required sections (Description, Getting
|
||||||
Started, Rationale, Design, TODO, License, Author)
|
Started, Rationale, Design, TODO, License, Author)
|
||||||
- [ ] `LICENSE` file exists and matches the README
|
- [ ] `LICENSE` file exists and matches the README
|
||||||
- [ ] `REPO_POLICIES.md` exists and version date is current with the
|
- [ ] `REPO_POLICIES.md` exists and version date is current — fetch from
|
||||||
[authoritative source](https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/REPO_POLICIES.md)
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/REPO_POLICIES.md`
|
||||||
- [ ] `.gitignore` is comprehensive (OS, editor, language artifacts, secrets) —
|
- [ ] `.gitignore` is comprehensive (OS, editor, language artifacts, secrets) —
|
||||||
fetch from `https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitignore`
|
fetch from `https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitignore`
|
||||||
if missing
|
if missing
|
||||||
- [ ] `.editorconfig` exists
|
- [ ] `.editorconfig` exists — fetch from
|
||||||
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.editorconfig`
|
||||||
- [ ] `Dockerfile` and `.dockerignore` exist; Dockerfile runs `make check` as a
|
- [ ] `Dockerfile` and `.dockerignore` exist; Dockerfile runs `make check` as a
|
||||||
build step
|
build step — fetch `.dockerignore` from
|
||||||
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.dockerignore`
|
||||||
- [ ] Gitea Actions workflow in `.gitea/workflows/` runs `docker build .` on
|
- [ ] Gitea Actions workflow in `.gitea/workflows/` runs `docker build .` on
|
||||||
push
|
push — reference
|
||||||
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitea/workflows/check.yml`
|
||||||
- [ ] Language-specific config:
|
- [ ] Language-specific config:
|
||||||
- [ ] Go: `go.mod`, `go.sum`, `.golangci.yml`
|
- [ ] Go: `go.mod`, `go.sum`, `.golangci.yml` (fetch from
|
||||||
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.golangci.yml`)
|
||||||
- [ ] JS: `package.json`, `yarn.lock`, `.prettierrc`, `.prettierignore`
|
- [ ] JS: `package.json`, `yarn.lock`, `.prettierrc`, `.prettierignore`
|
||||||
|
(fetch from
|
||||||
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.prettierrc` and
|
||||||
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.prettierignore`)
|
||||||
- [ ] Python: `pyproject.toml`
|
- [ ] Python: `pyproject.toml`
|
||||||
- [ ] Docs/writing: `.prettierrc`, `.prettierignore`
|
- [ ] Docs/writing: `.prettierrc`, `.prettierignore` (same URLs as above)
|
||||||
|
|
||||||
## Makefile
|
# Makefile
|
||||||
|
|
||||||
- [ ] `Makefile` exists in root — reference the
|
- [ ] `Makefile` exists in root — reference
|
||||||
[model Makefile](https://git.eeqj.de/sneak/prompts/raw/branch/main/Makefile)
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/Makefile`
|
||||||
- [ ] Has targets: `test`, `lint`, `fmt`, `fmt-check`, `check`, `docker`,
|
- [ ] Has targets: `test`, `lint`, `fmt`, `fmt-check`, `check`, `docker`,
|
||||||
`hooks`
|
`hooks`
|
||||||
- [ ] `make check` does not modify any files in the repo
|
- [ ] `make check` does not modify any files in the repo
|
||||||
- [ ] `make test` has a 30-second timeout
|
- [ ] `make test` has a 30-second timeout
|
||||||
|
- [ ] `make test` runs real tests, not a no-op (at minimum, import/compile
|
||||||
|
check)
|
||||||
- [ ] `make check` passes on current branch
|
- [ ] `make check` passes on current branch
|
||||||
|
|
||||||
## Formatting
|
# Formatting
|
||||||
|
|
||||||
- [ ] Platform-standard formatter is configured (`black`, `prettier`, `go fmt`)
|
- [ ] Platform-standard formatter is configured (`black`, `prettier`, `go fmt`)
|
||||||
- [ ] Default formatter config, only exception: four-space indents (except Go)
|
- [ ] Default formatter config, only exception: four-space indents (except Go)
|
||||||
- [ ] All files pass `make fmt-check`
|
- [ ] All files pass `make fmt-check`
|
||||||
|
|
||||||
## Git Hygiene
|
# Git Hygiene
|
||||||
|
|
||||||
- [ ] Pre-commit hook is installed (`make hooks`)
|
- [ ] Pre-commit hook is installed (`make hooks`)
|
||||||
- [ ] No secrets in the repo (`.env`, keys, credentials)
|
- [ ] No secrets in the repo (`.env`, keys, credentials)
|
||||||
@@ -58,14 +71,14 @@ with your task.
|
|||||||
pinned by cryptographic hash with version/date comment
|
pinned by cryptographic hash with version/date comment
|
||||||
- [ ] Using `yarn`, not `npm` (JS projects)
|
- [ ] Using `yarn`, not `npm` (JS projects)
|
||||||
|
|
||||||
## Directory Structure
|
# Directory Structure
|
||||||
|
|
||||||
- [ ] No unnecessary files in repo root
|
- [ ] No unnecessary files in repo root
|
||||||
- [ ] Files organized into canonical subdirectories (`bin/`, `cmd/`, `docs/`,
|
- [ ] Files organized into canonical subdirectories (`bin/`, `cmd/`, `docs/`,
|
||||||
`internal/`, `static/`, etc.)
|
`internal/`, `static/`, etc.)
|
||||||
- [ ] Go migrations in `internal/db/migrations/` and embedded in binary
|
- [ ] Go migrations in `internal/db/migrations/` and embedded in binary
|
||||||
|
|
||||||
## Final
|
# Final
|
||||||
|
|
||||||
- [ ] `make check` passes
|
- [ ] `make check` passes
|
||||||
- [ ] `docker build` succeeds
|
- [ ] `docker build` succeeds
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
# Go HTTP Server Conventions
|
---
|
||||||
|
title: Go HTTP Server Conventions
|
||||||
|
last_modified: 2026-02-22
|
||||||
|
---
|
||||||
|
|
||||||
This document defines the architectural patterns, design decisions, and
|
This document defines the architectural patterns, design decisions, and
|
||||||
conventions for building Go HTTP servers. All new projects must follow these
|
conventions for building Go HTTP servers. All new projects must follow these
|
||||||
standards.
|
standards.
|
||||||
|
|
||||||
## Table of Contents
|
# Table of Contents
|
||||||
|
|
||||||
1. [Required Libraries](#1-required-libraries)
|
1. [Required Libraries](#1-required-libraries)
|
||||||
2. [Project Structure](#2-project-structure)
|
2. [Project Structure](#2-project-structure)
|
||||||
@@ -23,7 +26,7 @@ standards.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1. Required Libraries
|
# 1. Required Libraries
|
||||||
|
|
||||||
These libraries are **mandatory** for all new projects:
|
These libraries are **mandatory** for all new projects:
|
||||||
|
|
||||||
@@ -42,7 +45,7 @@ These libraries are **mandatory** for all new projects:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. Project Structure
|
# 2. Project Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
project-root/
|
project-root/
|
||||||
@@ -84,7 +87,7 @@ project-root/
|
|||||||
└── Dockerfile
|
└── Dockerfile
|
||||||
```
|
```
|
||||||
|
|
||||||
### Key Principles
|
## Key Principles
|
||||||
|
|
||||||
- **`cmd/{appname}/`**: Only the entry point. Minimal logic, just bootstrapping.
|
- **`cmd/{appname}/`**: Only the entry point. Minimal logic, just bootstrapping.
|
||||||
- **`internal/`**: All application packages. Not importable by external
|
- **`internal/`**: All application packages. Not importable by external
|
||||||
@@ -94,9 +97,9 @@ project-root/
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. Dependency Injection (Uber fx)
|
# 3. Dependency Injection (Uber fx)
|
||||||
|
|
||||||
### Entry Point Pattern
|
## Entry Point Pattern
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// cmd/httpd/main.go
|
// cmd/httpd/main.go
|
||||||
@@ -141,7 +144,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Params Struct Pattern
|
## Params Struct Pattern
|
||||||
|
|
||||||
Every component that receives dependencies uses a params struct with `fx.In`:
|
Every component that receives dependencies uses a params struct with `fx.In`:
|
||||||
|
|
||||||
@@ -161,7 +164,7 @@ type Handlers struct {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Factory Function Pattern
|
## Factory Function Pattern
|
||||||
|
|
||||||
All components expose a `New` function with this signature:
|
All components expose a `New` function with this signature:
|
||||||
|
|
||||||
@@ -185,7 +188,7 @@ func New(lc fx.Lifecycle, params SomeParams) (*Something, error) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Dependency Order
|
## Dependency Order
|
||||||
|
|
||||||
Providers are resolved automatically by fx, but conceptually follow this order:
|
Providers are resolved automatically by fx, but conceptually follow this order:
|
||||||
|
|
||||||
@@ -201,9 +204,9 @@ Providers are resolved automatically by fx, but conceptually follow this order:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. Server Architecture
|
# 4. Server Architecture
|
||||||
|
|
||||||
### Server Struct
|
## Server Struct
|
||||||
|
|
||||||
The Server struct is the central orchestrator:
|
The Server struct is the central orchestrator:
|
||||||
|
|
||||||
@@ -234,7 +237,7 @@ type Server struct {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Server Factory
|
## Server Factory
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func New(lc fx.Lifecycle, params ServerParams) (*Server, error) {
|
func New(lc fx.Lifecycle, params ServerParams) (*Server, error) {
|
||||||
@@ -259,7 +262,7 @@ func New(lc fx.Lifecycle, params ServerParams) (*Server, error) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### HTTP Server Setup
|
## HTTP Server Setup
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// internal/server/http.go
|
// internal/server/http.go
|
||||||
@@ -289,7 +292,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Signal Handling and Graceful Shutdown
|
## Signal Handling and Graceful Shutdown
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (s *Server) serve() int {
|
func (s *Server) serve() int {
|
||||||
@@ -333,9 +336,9 @@ func (s *Server) cleanShutdown() {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5. Routing (go-chi)
|
# 5. Routing (go-chi)
|
||||||
|
|
||||||
### Route Setup Pattern
|
## Route Setup Pattern
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// internal/server/routes.go
|
// internal/server/routes.go
|
||||||
@@ -378,7 +381,7 @@ func (s *Server) SetupRoutes() {
|
|||||||
s.router.Get("/login", auth(s.h.HandleLoginGET()).ServeHTTP)
|
s.router.Get("/login", auth(s.h.HandleLoginGET()).ServeHTTP)
|
||||||
|
|
||||||
// Health check (standard path)
|
// Health check (standard path)
|
||||||
s.router.Get("/.well-known/healthcheck.json", s.h.HandleHealthCheck())
|
s.router.Get("/.well-known/healthcheck", s.h.HandleHealthCheck())
|
||||||
|
|
||||||
// Protected route groups
|
// Protected route groups
|
||||||
if viper.GetString("METRICS_USERNAME") != "" {
|
if viper.GetString("METRICS_USERNAME") != "" {
|
||||||
@@ -390,7 +393,7 @@ func (s *Server) SetupRoutes() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Middleware Ordering (Critical)
|
## Middleware Ordering (Critical)
|
||||||
|
|
||||||
1. `middleware.Recoverer` - Panic recovery (must be first)
|
1. `middleware.Recoverer` - Panic recovery (must be first)
|
||||||
2. `middleware.RequestID` - Generate request IDs
|
2. `middleware.RequestID` - Generate request IDs
|
||||||
@@ -400,7 +403,7 @@ func (s *Server) SetupRoutes() {
|
|||||||
6. `middleware.Timeout(60s)` - Request timeout
|
6. `middleware.Timeout(60s)` - Request timeout
|
||||||
7. `sentryhttp.Handler` - Sentry error reporting (if enabled)
|
7. `sentryhttp.Handler` - Sentry error reporting (if enabled)
|
||||||
|
|
||||||
### API Versioning
|
## API Versioning
|
||||||
|
|
||||||
Use route groups for API versioning:
|
Use route groups for API versioning:
|
||||||
|
|
||||||
@@ -410,7 +413,7 @@ s.router.Route("/api/v1", func(r chi.Router) {
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
### Static File Serving
|
## Static File Serving
|
||||||
|
|
||||||
Static files are served at `/s/` prefix:
|
Static files are served at `/s/` prefix:
|
||||||
|
|
||||||
@@ -420,9 +423,9 @@ s.router.Mount("/s", http.StripPrefix("/s", http.FileServer(http.FS(static.Stati
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6. Handler Conventions
|
# 6. Handler Conventions
|
||||||
|
|
||||||
### Handler Base Struct
|
## Handler Base Struct
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// internal/handlers/handlers.go
|
// internal/handlers/handlers.go
|
||||||
@@ -455,7 +458,7 @@ func New(lc fx.Lifecycle, params HandlersParams) (*Handlers, error) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Closure-Based Handler Pattern
|
## Closure-Based Handler Pattern
|
||||||
|
|
||||||
All handlers return `http.HandlerFunc` using the closure pattern. This allows
|
All handlers return `http.HandlerFunc` using the closure pattern. This allows
|
||||||
initialization logic to run once when the handler is created:
|
initialization logic to run once when the handler is created:
|
||||||
@@ -477,7 +480,7 @@ func (s *Handlers) HandleIndex() http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### JSON Handler Pattern
|
## JSON Handler Pattern
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// internal/handlers/now.go
|
// internal/handlers/now.go
|
||||||
@@ -492,7 +495,7 @@ func (s *Handlers) HandleNow() http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Response Helpers
|
## Response Helpers
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// internal/handlers/handlers.go
|
// internal/handlers/handlers.go
|
||||||
@@ -512,7 +515,7 @@ func (s *Handlers) decodeJSON(w http.ResponseWriter, r *http.Request, v interfac
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Handler Naming Convention
|
## Handler Naming Convention
|
||||||
|
|
||||||
- `HandleIndex()` - Main page
|
- `HandleIndex()` - Main page
|
||||||
- `HandleLoginGET()` / `HandleLoginPOST()` - Form handlers with HTTP method
|
- `HandleLoginGET()` / `HandleLoginPOST()` - Form handlers with HTTP method
|
||||||
@@ -522,9 +525,9 @@ func (s *Handlers) decodeJSON(w http.ResponseWriter, r *http.Request, v interfac
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7. Middleware Conventions
|
# 7. Middleware Conventions
|
||||||
|
|
||||||
### Middleware Struct
|
## Middleware Struct
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// internal/middleware/middleware.go
|
// internal/middleware/middleware.go
|
||||||
@@ -548,7 +551,7 @@ func New(lc fx.Lifecycle, params MiddlewareParams) (*Middleware, error) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Middleware Signature
|
## Middleware Signature
|
||||||
|
|
||||||
All custom middleware methods return `func(http.Handler) http.Handler`:
|
All custom middleware methods return `func(http.Handler) http.Handler`:
|
||||||
|
|
||||||
@@ -567,7 +570,7 @@ func (s *Middleware) Auth() func(http.Handler) http.Handler {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Logging Middleware with Status Capture
|
## Logging Middleware with Status Capture
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type loggingResponseWriter struct {
|
type loggingResponseWriter struct {
|
||||||
@@ -611,7 +614,7 @@ func (s *Middleware) Logging() func(http.Handler) http.Handler {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### CORS Middleware
|
## CORS Middleware
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (s *Middleware) CORS() func(http.Handler) http.Handler {
|
func (s *Middleware) CORS() func(http.Handler) http.Handler {
|
||||||
@@ -626,7 +629,7 @@ func (s *Middleware) CORS() func(http.Handler) http.Handler {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Metrics Middleware
|
## Metrics Middleware
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (s *Middleware) Metrics() func(http.Handler) http.Handler {
|
func (s *Middleware) Metrics() func(http.Handler) http.Handler {
|
||||||
@@ -652,9 +655,9 @@ func (s *Middleware) MetricsAuth() func(http.Handler) http.Handler {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8. Configuration (Viper)
|
# 8. Configuration (Viper)
|
||||||
|
|
||||||
### Config Struct
|
## Config Struct
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// internal/config/config.go
|
// internal/config/config.go
|
||||||
@@ -677,7 +680,7 @@ type Config struct {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Configuration Loading
|
## Configuration Loading
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func New(lc fx.Lifecycle, params ConfigParams) (*Config, error) {
|
func New(lc fx.Lifecycle, params ConfigParams) (*Config, error) {
|
||||||
@@ -735,7 +738,7 @@ func New(lc fx.Lifecycle, params ConfigParams) (*Config, error) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Configuration Precedence
|
## Configuration Precedence
|
||||||
|
|
||||||
1. **Environment variables** (highest priority via `AutomaticEnv()`)
|
1. **Environment variables** (highest priority via `AutomaticEnv()`)
|
||||||
2. **`.env` file** (loaded via `godotenv/autoload` import)
|
2. **`.env` file** (loaded via `godotenv/autoload` import)
|
||||||
@@ -743,7 +746,7 @@ func New(lc fx.Lifecycle, params ConfigParams) (*Config, error) {
|
|||||||
`~/.config/{appname}/{appname}.yaml`
|
`~/.config/{appname}/{appname}.yaml`
|
||||||
4. **Defaults** (lowest priority)
|
4. **Defaults** (lowest priority)
|
||||||
|
|
||||||
### Environment Loading
|
## Environment Loading
|
||||||
|
|
||||||
Import godotenv with autoload to automatically load `.env` files:
|
Import godotenv with autoload to automatically load `.env` files:
|
||||||
|
|
||||||
@@ -755,9 +758,9 @@ import (
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9. Logging (slog)
|
# 9. Logging (slog)
|
||||||
|
|
||||||
### Logger Struct
|
## Logger Struct
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// internal/logger/logger.go
|
// internal/logger/logger.go
|
||||||
@@ -773,7 +776,7 @@ type Logger struct {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Logger Setup with TTY Detection
|
## Logger Setup with TTY Detection
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func New(lc fx.Lifecycle, params LoggerParams) (*Logger, error) {
|
func New(lc fx.Lifecycle, params LoggerParams) (*Logger, error) {
|
||||||
@@ -807,7 +810,7 @@ func New(lc fx.Lifecycle, params LoggerParams) (*Logger, error) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Logger Methods
|
## Logger Methods
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (l *Logger) EnableDebugLogging() {
|
func (l *Logger) EnableDebugLogging() {
|
||||||
@@ -828,7 +831,7 @@ func (l *Logger) Identify() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Logging Patterns
|
## Logging Patterns
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Info with fields
|
// Info with fields
|
||||||
@@ -864,9 +867,9 @@ s.log.Info("request",
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 10. Database Wrapper
|
# 10. Database Wrapper
|
||||||
|
|
||||||
### Database Struct
|
## Database Struct
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// internal/database/database.go
|
// internal/database/database.go
|
||||||
@@ -883,7 +886,7 @@ type Database struct {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Database Factory with Lifecycle
|
## Database Factory with Lifecycle
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func New(lc fx.Lifecycle, params DatabaseParams) (*Database, error) {
|
func New(lc fx.Lifecycle, params DatabaseParams) (*Database, error) {
|
||||||
@@ -910,7 +913,7 @@ func New(lc fx.Lifecycle, params DatabaseParams) (*Database, error) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Usage Pattern
|
## Usage Pattern
|
||||||
|
|
||||||
The Database struct is injected into handlers and other services:
|
The Database struct is injected into handlers and other services:
|
||||||
|
|
||||||
@@ -931,9 +934,9 @@ func (s *Handlers) HandleSomething() http.HandlerFunc {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 11. Globals Package
|
# 11. Globals Package
|
||||||
|
|
||||||
### Package Variables and Struct
|
## Package Variables and Struct
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// internal/globals/globals.go
|
// internal/globals/globals.go
|
||||||
@@ -965,7 +968,7 @@ func New(lc fx.Lifecycle) (*Globals, error) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Setting Globals in Main
|
## Setting Globals in Main
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// cmd/httpd/main.go
|
// cmd/httpd/main.go
|
||||||
@@ -983,7 +986,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Build-Time Variable Injection
|
## Build-Time Variable Injection
|
||||||
|
|
||||||
Use ldflags to inject version information at build time:
|
Use ldflags to inject version information at build time:
|
||||||
|
|
||||||
@@ -997,9 +1000,9 @@ build:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 12. Static Assets & Templates
|
# 12. Static Assets & Templates
|
||||||
|
|
||||||
### Static File Embedding
|
## Static File Embedding
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// static/static.go
|
// static/static.go
|
||||||
@@ -1024,7 +1027,7 @@ static/
|
|||||||
└── jquery-3.5.1.slim.min.js
|
└── jquery-3.5.1.slim.min.js
|
||||||
```
|
```
|
||||||
|
|
||||||
### Template Embedding and Lazy Parsing
|
## Template Embedding and Lazy Parsing
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// templates/templates.go
|
// templates/templates.go
|
||||||
@@ -1047,7 +1050,7 @@ func GetParsed() *template.Template {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Template Composition
|
## Template Composition
|
||||||
|
|
||||||
Templates use Go's template composition:
|
Templates use Go's template composition:
|
||||||
|
|
||||||
@@ -1062,7 +1065,7 @@ Templates use Go's template composition:
|
|||||||
{{ template "pagefooter.html" . }} {{ template "htmlfooter.html" . }}
|
{{ template "pagefooter.html" . }} {{ template "htmlfooter.html" . }}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Static Asset References
|
## Static Asset References
|
||||||
|
|
||||||
Reference static files with `/s/` prefix:
|
Reference static files with `/s/` prefix:
|
||||||
|
|
||||||
@@ -1074,9 +1077,9 @@ Reference static files with `/s/` prefix:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 13. Health Check
|
# 13. Health Check
|
||||||
|
|
||||||
### Health Check Service
|
## Health Check Service
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// internal/healthcheck/healthcheck.go
|
// internal/healthcheck/healthcheck.go
|
||||||
@@ -1112,7 +1115,7 @@ func New(lc fx.Lifecycle, params HealthcheckParams) (*Healthcheck, error) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Health Check Response
|
## Health Check Response
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type HealthcheckResponse struct {
|
type HealthcheckResponse struct {
|
||||||
@@ -1142,19 +1145,19 @@ func (s *Healthcheck) Healthcheck() *HealthcheckResponse {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Standard Endpoint
|
## Standard Endpoint
|
||||||
|
|
||||||
Health check is served at the standard `.well-known` path:
|
Health check is served at the standard `.well-known` path:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
s.router.Get("/.well-known/healthcheck.json", s.h.HandleHealthCheck())
|
s.router.Get("/.well-known/healthcheck", s.h.HandleHealthCheck())
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 14. External Integrations
|
# 14. External Integrations
|
||||||
|
|
||||||
### Sentry Error Reporting
|
## Sentry Error Reporting
|
||||||
|
|
||||||
Sentry is conditionally enabled based on `SENTRY_DSN` environment variable:
|
Sentry is conditionally enabled based on `SENTRY_DSN` environment variable:
|
||||||
|
|
||||||
@@ -1199,7 +1202,7 @@ if s.sentryEnabled {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Prometheus Metrics
|
## Prometheus Metrics
|
||||||
|
|
||||||
Metrics are conditionally enabled and protected by basic auth:
|
Metrics are conditionally enabled and protected by basic auth:
|
||||||
|
|
||||||
@@ -1218,7 +1221,7 @@ if viper.GetString("METRICS_USERNAME") != "" {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Environment Variables Summary
|
## Environment Variables Summary
|
||||||
|
|
||||||
| Variable | Description | Default |
|
| Variable | Description | Default |
|
||||||
| ------------------ | -------------------------------- | ------- |
|
| ------------------ | -------------------------------- | ------- |
|
||||||
@@ -1229,3 +1232,11 @@ if viper.GetString("METRICS_USERNAME") != "" {
|
|||||||
| `MAINTENANCE_MODE` | Enable maintenance mode | false |
|
| `MAINTENANCE_MODE` | Enable maintenance mode | false |
|
||||||
| `METRICS_USERNAME` | Basic auth username for /metrics | "" |
|
| `METRICS_USERNAME` | Basic auth username for /metrics | "" |
|
||||||
| `METRICS_PASSWORD` | Basic auth password for /metrics | "" |
|
| `METRICS_PASSWORD` | Basic auth password for /metrics | "" |
|
||||||
|
|
||||||
|
# Author
|
||||||
|
|
||||||
|
[@sneak](https://sneak.berlin) <[sneak@sneak.berlin](mailto:sneak@sneak.berlin)>
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
|
MIT. See [LICENSE](../LICENSE).
|
||||||
|
|||||||
514
prompts/LLM_PROSE_TELLS.md
Normal file
514
prompts/LLM_PROSE_TELLS.md
Normal file
@@ -0,0 +1,514 @@
|
|||||||
|
# LLM Prose Tells
|
||||||
|
|
||||||
|
Every pattern in this document shows up in human writing occasionally. They
|
||||||
|
become diagnostic only through density. A person might use one or two across an
|
||||||
|
entire essay, but LLM output packs fifteen into a single paragraph.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Sentence Structure
|
||||||
|
|
||||||
|
### The Em-Dash Pivot: "Not X—but Y"
|
||||||
|
|
||||||
|
A negation followed by an em-dash and a reframe.
|
||||||
|
|
||||||
|
> "It's not just a tool—it's a paradigm shift." "This isn't about
|
||||||
|
> technology—it's about trust."
|
||||||
|
|
||||||
|
The single most recognizable LLM construction. Models produce this at roughly 10
|
||||||
|
to 50x the rate of human writers. Four of them in one essay and you know what
|
||||||
|
you're reading.
|
||||||
|
|
||||||
|
### Em-Dash Overuse Generally
|
||||||
|
|
||||||
|
Even outside the "not X but Y" pivot, models use em-dashes at far higher rates
|
||||||
|
than human writers. They substitute em-dashes for commas, semicolons,
|
||||||
|
parentheses, colons, and periods, often multiple times per paragraph. A human
|
||||||
|
writer might use one or two in an entire piece for a specific parenthetical
|
||||||
|
effect. Models scatter them everywhere because the em-dash can stand in for any
|
||||||
|
other punctuation mark, so they default to it. More than two or three per page
|
||||||
|
is a meaningful signal on its own.
|
||||||
|
|
||||||
|
### The Colon Elaboration
|
||||||
|
|
||||||
|
A short declarative clause, then a colon, then a longer explanation.
|
||||||
|
|
||||||
|
> "The answer is simple: we need to rethink our approach from the ground up."
|
||||||
|
|
||||||
|
Models reach for this in every other paragraph. The construction is perfectly
|
||||||
|
normal. The frequency gives it away.
|
||||||
|
|
||||||
|
### The Triple Construction
|
||||||
|
|
||||||
|
> "It's fast, it's scalable, and it's open source."
|
||||||
|
|
||||||
|
Three parallel items in a list, usually escalating. Always exactly three (rarely
|
||||||
|
two, never four) with strict grammatical parallelism that human writers rarely
|
||||||
|
bother maintaining.
|
||||||
|
|
||||||
|
### The Staccato Burst
|
||||||
|
|
||||||
|
> "This matters. It always has. And it always will." "The data is clear. The
|
||||||
|
> trend is undeniable. The conclusion is obvious."
|
||||||
|
|
||||||
|
Runs of very short sentences at the same cadence. Human writers use a short
|
||||||
|
sentence for emphasis occasionally, but stacking three or four of them in a row
|
||||||
|
at matching length creates a mechanical regularity that reads as generated.
|
||||||
|
|
||||||
|
### The Two-Clause Compound Sentence
|
||||||
|
|
||||||
|
Possibly the most pervasive structural tell, and easy to miss because each
|
||||||
|
individual instance looks like normal English. The model produces sentence after
|
||||||
|
sentence where an independent clause is followed by a comma, a conjunction
|
||||||
|
("and," "but," "which," "because"), and a second independent clause of similar
|
||||||
|
length. Every sentence becomes two balanced halves joined in the middle.
|
||||||
|
|
||||||
|
> "The construction itself is perfectly normal, which is why the frequency is
|
||||||
|
> what gives it away." "They contain zero information, and the actual point
|
||||||
|
> always comes in the paragraph that follows them." "The qualifier never changes
|
||||||
|
> the argument that follows it, and its purpose is to perform nuance rather than
|
||||||
|
> to express an actual reservation."
|
||||||
|
|
||||||
|
Human prose has sentences with one clause, sentences with three, sentences that
|
||||||
|
start with a subordinate clause before reaching the main one, sentences that
|
||||||
|
embed their complexity in the middle. When every sentence on the page has that
|
||||||
|
same two-part structure, the rhythm becomes monotonous in a way that's hard to
|
||||||
|
pinpoint but easy to feel.
|
||||||
|
|
||||||
|
### Uniform Sentences Per Paragraph
|
||||||
|
|
||||||
|
Model-generated paragraphs contain between three and five sentences. This count
|
||||||
|
holds steady across an entire piece. If the first paragraph has four sentences,
|
||||||
|
every subsequent paragraph will too. Human writers are much more varied (a
|
||||||
|
single sentence followed by one that runs eight or nine) because they follow the
|
||||||
|
shape of an idea, not a template.
|
||||||
|
|
||||||
|
### The Dramatic Fragment
|
||||||
|
|
||||||
|
Sentence fragments used as standalone paragraphs for emphasis, like "Full stop."
|
||||||
|
or "Let that sink in." on their own line. Using one in an entire essay is a
|
||||||
|
reasonable stylistic choice, but models drop them in once per section or more,
|
||||||
|
at which point it becomes a habit rather than a deliberate decision.
|
||||||
|
|
||||||
|
### The Pivot Paragraph
|
||||||
|
|
||||||
|
> "But here's where it gets interesting." "Which raises an uncomfortable truth."
|
||||||
|
|
||||||
|
One-sentence paragraphs that exist only to transition between ideas. They
|
||||||
|
contain zero information. The actual point is always in the next paragraph.
|
||||||
|
Delete every one of these and the piece reads better.
|
||||||
|
|
||||||
|
### The Parenthetical Qualifier
|
||||||
|
|
||||||
|
> "This is, of course, a simplification." "There are, to be fair, exceptions."
|
||||||
|
|
||||||
|
Parenthetical asides inserted to look thoughtful. The qualifier never changes
|
||||||
|
the argument that follows it. Its purpose is to perform nuance, not to express a
|
||||||
|
real reservation about what's being said.
|
||||||
|
|
||||||
|
### The Unnecessary Contrast
|
||||||
|
|
||||||
|
Models append a contrasting clause to statements that don't need one, tacking on
|
||||||
|
"whereas," "as opposed to," "unlike," or "except that" to draw a comparison the
|
||||||
|
reader could already infer.
|
||||||
|
|
||||||
|
> "Models write one register above where a human would, whereas human writers
|
||||||
|
> tend to match register to context."
|
||||||
|
|
||||||
|
The first clause already makes the point. The contrasting clause restates it
|
||||||
|
from the other direction. If you delete the "whereas" clause and the sentence
|
||||||
|
still says everything it needs to, the contrast was filler.
|
||||||
|
|
||||||
|
### Unnecessary Elaboration
|
||||||
|
|
||||||
|
Models keep going after the sentence has already made its point, tacking on
|
||||||
|
clarifying phrases, adverbial modifiers, or restatements that add nothing.
|
||||||
|
|
||||||
|
> "A person might lean on one or two of these habits across an entire essay, but
|
||||||
|
> LLM output will use fifteen of them per paragraph, consistently, throughout
|
||||||
|
> the entire piece."
|
||||||
|
|
||||||
|
This sentence could end at "paragraph." The words after it just repeat what "per
|
||||||
|
paragraph" already means. Models do this because they're optimizing for clarity
|
||||||
|
at the expense of concision, and because their training rewards thoroughness.
|
||||||
|
The result is prose that feels padded. If you can cut the last third of a
|
||||||
|
sentence without losing any meaning, the last third shouldn't be there.
|
||||||
|
|
||||||
|
### The Question-Then-Answer
|
||||||
|
|
||||||
|
> "So what does this mean for the average user? It means everything."
|
||||||
|
|
||||||
|
A rhetorical question immediately followed by its own answer. Models do this two
|
||||||
|
or three times per piece because it fakes forward momentum. A human writer might
|
||||||
|
do it once.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Word Choice
|
||||||
|
|
||||||
|
### Overused Intensifiers
|
||||||
|
|
||||||
|
The following words appear at dramatically elevated rates in model output:
|
||||||
|
"crucial," "vital," "robust," "comprehensive," "fundamental," "arguably,"
|
||||||
|
"straightforward," "noteworthy," "realm," "landscape," "leverage" (as a verb),
|
||||||
|
"delve," "tapestry," "multifaceted," "nuanced" (which models apply to their own
|
||||||
|
analysis with startling regularity), "pivotal," "unprecedented" (frequently
|
||||||
|
applied to things with plenty of precedent), "navigate," "foster,"
|
||||||
|
"underscores," "resonates," "embark," "streamline," and "spearhead." Three or
|
||||||
|
more on the same page is a strong signal.
|
||||||
|
|
||||||
|
### Elevated Register Drift
|
||||||
|
|
||||||
|
Models write one register above where a human would. "Use" becomes "utilize."
|
||||||
|
"Start" becomes "commence." "Help" becomes "facilitate." "Show" becomes
|
||||||
|
"demonstrate." "Try" becomes "endeavor." "Change" becomes "transform." "Make"
|
||||||
|
becomes "craft." The tendency holds regardless of topic or audience.
|
||||||
|
|
||||||
|
### Filler Adverbs
|
||||||
|
|
||||||
|
"Importantly," "essentially," "fundamentally," "ultimately," "inherently,"
|
||||||
|
"particularly," "increasingly." Dropped in to signal that something matters,
|
||||||
|
which is unnecessary when the writing itself already makes the importance clear.
|
||||||
|
|
||||||
|
### The "Almost" Hedge
|
||||||
|
|
||||||
|
Models rarely commit to an unqualified statement. Instead of saying a pattern
|
||||||
|
"always" or "never" does something, they write "almost always," "almost never,"
|
||||||
|
"almost certainly," "almost exclusively." The word "almost" shows up at
|
||||||
|
extraordinary density in model-generated analytical prose. It's a micro-hedge,
|
||||||
|
less obvious than the full hedge stack but just as diagnostic when it appears
|
||||||
|
ten or fifteen times in a single document.
|
||||||
|
|
||||||
|
### "In an era of..."
|
||||||
|
|
||||||
|
> "In an era of rapid technological change..."
|
||||||
|
|
||||||
|
A model habit as an essay opener. The model uses it to stall while it figures
|
||||||
|
out what the actual argument is. Human writers don't begin a piece by zooming
|
||||||
|
out to the civilizational scale before they've said anything specific.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Rhetorical Patterns
|
||||||
|
|
||||||
|
### The Balanced Take
|
||||||
|
|
||||||
|
> "While X has its drawbacks, it also offers significant benefits."
|
||||||
|
|
||||||
|
Every argument followed by a concession, every criticism softened. A direct
|
||||||
|
artifact of RLHF training, which penalizes strong stances. Models reflexively
|
||||||
|
both-sides everything even when a clear position would serve the reader better.
|
||||||
|
|
||||||
|
### The Throat-Clearing Opener
|
||||||
|
|
||||||
|
> "In today's rapidly evolving digital landscape, the question of data privacy
|
||||||
|
> has never been more important."
|
||||||
|
|
||||||
|
The first paragraph of most model-generated essays adds no information. Delete
|
||||||
|
it and the piece improves immediately. The actual argument starts in paragraph
|
||||||
|
two.
|
||||||
|
|
||||||
|
### The False Conclusion
|
||||||
|
|
||||||
|
> "At the end of the day, what matters most is..." "Moving forward, we must..."
|
||||||
|
|
||||||
|
The high school "In conclusion,..." dressed up for a professional audience.
|
||||||
|
Signals that the model is wrapping up without actually landing on anything.
|
||||||
|
|
||||||
|
### The Sycophantic Frame
|
||||||
|
|
||||||
|
> "Great question!" "That's a really insightful observation."
|
||||||
|
|
||||||
|
No one who writes for a living opens by complimenting the assignment.
|
||||||
|
|
||||||
|
### The Listicle Instinct
|
||||||
|
|
||||||
|
Models default to numbered or bulleted lists even when prose would be more
|
||||||
|
appropriate. The lists contain exactly 3, 5, 7, or 10 items (never 4, 6, or 9),
|
||||||
|
use rigidly parallel grammar, and get introduced with a preamble like "Here are
|
||||||
|
the key considerations:"
|
||||||
|
|
||||||
|
### The Hedge Stack
|
||||||
|
|
||||||
|
> "It's worth noting that, while this may not be universally applicable, in many
|
||||||
|
> cases it can potentially offer significant benefits."
|
||||||
|
|
||||||
|
Five hedges in one sentence ("worth noting," "while," "may not be," "in many
|
||||||
|
cases," "can potentially"), communicating nothing. The model would rather be
|
||||||
|
vague than risk being wrong about anything.
|
||||||
|
|
||||||
|
### The Empathy Performance
|
||||||
|
|
||||||
|
> "This can be a deeply challenging experience." "Your feelings are valid."
|
||||||
|
|
||||||
|
Generic emotional language that could apply equally to a bad day at work or a
|
||||||
|
natural disaster. That interchangeability is what makes it identifiable.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Structural Tells
|
||||||
|
|
||||||
|
### Symmetrical Section Length
|
||||||
|
|
||||||
|
If the first section of a model-generated essay runs about 150 words, every
|
||||||
|
subsequent section will fall between 130 and 170. Human writing is much more
|
||||||
|
uneven, with 50 words in one section and 400 in the next.
|
||||||
|
|
||||||
|
### The Five-Paragraph Prison
|
||||||
|
|
||||||
|
Model essays follow a rigid introduction-body-conclusion arc even when nobody
|
||||||
|
asked for one. The introduction previews the argument, the body presents 3 to 5
|
||||||
|
points, and then the conclusion restates the thesis using slightly different
|
||||||
|
words.
|
||||||
|
|
||||||
|
### Connector Addiction
|
||||||
|
|
||||||
|
Look at the first word of each paragraph in model output. You'll find an
|
||||||
|
unbroken chain of transition words: "However," "Furthermore," "Moreover,"
|
||||||
|
"Additionally," "That said," "To that end," "With that in mind," "Building on
|
||||||
|
this." Human prose moves between ideas without announcing every transition.
|
||||||
|
|
||||||
|
### Absence of Mess
|
||||||
|
|
||||||
|
Model prose doesn't contradict itself mid-paragraph and then catch the
|
||||||
|
contradiction. It doesn't go on a tangent and have to walk it back, use an
|
||||||
|
obscure idiom without explaining it, make a joke that risks falling flat, leave
|
||||||
|
a thought genuinely unfinished, or keep a sentence the writer liked the sound of
|
||||||
|
even though it doesn't quite work.
|
||||||
|
|
||||||
|
Human writing does all of those things regularly. That total absence of rough
|
||||||
|
patches and false starts is one of the strongest signals that text was
|
||||||
|
machine-generated.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Framing Tells
|
||||||
|
|
||||||
|
### "Broader Implications"
|
||||||
|
|
||||||
|
> "This has implications far beyond just the tech industry."
|
||||||
|
|
||||||
|
Zooming out to claim broader significance without substantiating it. The model
|
||||||
|
has learned that essays are supposed to gesture at big ideas, so it gestures.
|
||||||
|
Nothing concrete is behind the gesture.
|
||||||
|
|
||||||
|
### "It's important to note that..."
|
||||||
|
|
||||||
|
This phrase and its variants ("it's worth noting," "it bears mentioning," "it
|
||||||
|
should be noted") appear at absurd rates in model output. They function as
|
||||||
|
verbal tics before a qualification the model believes someone expects.
|
||||||
|
|
||||||
|
### The Metaphor Crutch
|
||||||
|
|
||||||
|
Models rely on a small, predictable set of metaphors ("double-edged sword," "tip
|
||||||
|
of the iceberg," "north star," "building blocks," "elephant in the room,"
|
||||||
|
"perfect storm," "game-changer") and reach for them with unusual regularity
|
||||||
|
across every topic. The pool is noticeably smaller than what human writers draw
|
||||||
|
from.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How to Actually Spot It
|
||||||
|
|
||||||
|
No single pattern on this list proves anything by itself. Humans use em-dashes.
|
||||||
|
Humans write "crucial." Humans ask rhetorical questions.
|
||||||
|
|
||||||
|
What gives it away is how many of these show up at once. Model output will hit
|
||||||
|
10 to 20 of these patterns per page. Human writing might trigger 2 or 3,
|
||||||
|
distributed unevenly, mixed with idiosyncratic constructions no model would
|
||||||
|
produce. When every paragraph on the page reads like it came from the same
|
||||||
|
careful, balanced, slightly formal, structurally predictable process, it was
|
||||||
|
generated by one.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Copyediting Checklist: Removing LLM Tells
|
||||||
|
|
||||||
|
Follow this checklist when editing any document to remove machine-generated
|
||||||
|
patterns. Go through the entire list for every piece. Do at least two full
|
||||||
|
passes, because fixing one pattern often introduces another.
|
||||||
|
|
||||||
|
### Pass 1: Word-Level Cleanup
|
||||||
|
|
||||||
|
1. Search the document for every word in the overused intensifiers list
|
||||||
|
("crucial," "vital," "robust," "comprehensive," "fundamental," "arguably,"
|
||||||
|
"straightforward," "noteworthy," "realm," "landscape," "leverage," "delve,"
|
||||||
|
"tapestry," "multifaceted," "nuanced," "pivotal," "unprecedented,"
|
||||||
|
"navigate," "foster," "underscores," "resonates," "embark," "streamline,"
|
||||||
|
"spearhead") and replace each one with a plainer word, or delete it if the
|
||||||
|
sentence works without it.
|
||||||
|
|
||||||
|
2. Search for filler adverbs ("importantly," "essentially," "fundamentally,"
|
||||||
|
"ultimately," "inherently," "particularly," "increasingly") and delete every
|
||||||
|
instance where the sentence still makes sense without it. That will be most
|
||||||
|
of them.
|
||||||
|
|
||||||
|
3. Look for elevated register drift ("utilize," "commence," "facilitate,"
|
||||||
|
"demonstrate," "endeavor," "transform," "craft" and similar) and replace with
|
||||||
|
the simpler word.
|
||||||
|
|
||||||
|
4. Search for "it's important to note," "it's worth noting," "it bears
|
||||||
|
mentioning," and "it should be noted" and delete the phrase in every case.
|
||||||
|
The sentence that follows always stands on its own.
|
||||||
|
|
||||||
|
5. Search for the stock metaphors ("double-edged sword," "tip of the iceberg,"
|
||||||
|
"north star," "building blocks," "elephant in the room," "perfect storm,"
|
||||||
|
"game-changer," "at the end of the day") and replace them with something
|
||||||
|
specific to the topic, or just state the point directly.
|
||||||
|
|
||||||
|
6. Search for "almost" used as a hedge ("almost always," "almost never," "almost
|
||||||
|
certainly," "almost exclusively") and decide in each case whether to commit
|
||||||
|
to the unqualified claim or to drop the sentence entirely. If the claim needs
|
||||||
|
"almost" to be true, it might not be worth making.
|
||||||
|
|
||||||
|
7. Search for em-dashes and replace each one with the punctuation mark that
|
||||||
|
would normally be used in that position (comma, semicolon, colon, period, or
|
||||||
|
parentheses). If you can't identify which one it should be, the sentence
|
||||||
|
needs to be restructured.
|
||||||
|
|
||||||
|
### Pass 2: Sentence-Level Restructuring
|
||||||
|
|
||||||
|
8. Find every em-dash pivot ("not X...but Y," "not just X...Y," "more than
|
||||||
|
X...Y") and rewrite it as two separate clauses or a single sentence that
|
||||||
|
makes the point without the negation-then-correction structure.
|
||||||
|
|
||||||
|
9. Find every colon elaboration and check whether it's doing real work. If the
|
||||||
|
clause before the colon could be deleted without losing meaning, rewrite the
|
||||||
|
sentence to start with the substance that comes after the colon.
|
||||||
|
|
||||||
|
10. Find every triple construction (three parallel items in a row) and either
|
||||||
|
reduce it to two, expand it to four or more, or break the parallelism so the
|
||||||
|
items don't share the same grammatical structure.
|
||||||
|
|
||||||
|
11. Find every staccato burst (three or more short sentences in a row at similar
|
||||||
|
length) and combine at least two of them into a longer sentence, or vary
|
||||||
|
their lengths so they don't land at the same cadence.
|
||||||
|
|
||||||
|
12. Find every unnecessary contrast ("whereas," "as opposed to," "unlike," "as
|
||||||
|
compared to," "except that") and check whether the contrasting clause adds
|
||||||
|
information not already obvious from the main clause. If the sentence says
|
||||||
|
the same thing twice from two directions, delete the contrast.
|
||||||
|
|
||||||
|
13. Check for the two-clause compound sentence pattern. If most sentences in a
|
||||||
|
passage follow the "\[clause\], \[conjunction\] \[clause\]" structure,
|
||||||
|
rewrite some of them. Break a few into two sentences. Start some with a
|
||||||
|
subordinate clause. Embed a relative clause in the middle of one instead of
|
||||||
|
appending it at the end. The goal is variety in sentence shape, not just
|
||||||
|
sentence length.
|
||||||
|
|
||||||
|
14. Find every rhetorical question that is immediately followed by its own
|
||||||
|
answer and rewrite the passage as a direct statement.
|
||||||
|
|
||||||
|
15. Find every sentence fragment being used as its own paragraph and either
|
||||||
|
delete it or expand it into a complete sentence that adds actual
|
||||||
|
information.
|
||||||
|
|
||||||
|
16. Check for unnecessary elaboration at the end of sentences. Read the last
|
||||||
|
clause or phrase of each sentence and ask whether the sentence would lose
|
||||||
|
any meaning without it. If not, cut it.
|
||||||
|
|
||||||
|
17. Find every pivot paragraph ("But here's where it gets interesting." and
|
||||||
|
similar) and delete it. The paragraph after it always contains the actual
|
||||||
|
point.
|
||||||
|
|
||||||
|
### Pass 3: Paragraph and Section-Level Review
|
||||||
|
|
||||||
|
18. Check paragraph lengths across the piece and verify they actually vary. If
|
||||||
|
most paragraphs have between three and five sentences, rewrite some to be
|
||||||
|
one or two sentences and let others run to six or seven.
|
||||||
|
|
||||||
|
19. Check section lengths for suspicious uniformity. If every section is roughly
|
||||||
|
the same word count, combine some shorter ones or split a longer one
|
||||||
|
unevenly.
|
||||||
|
|
||||||
|
20. Check the first word of every paragraph for chains of connectors ("However,"
|
||||||
|
"Furthermore," "Moreover," "Additionally," "That said"). If more than two
|
||||||
|
transition words start consecutive paragraphs, rewrite those openings to
|
||||||
|
start with their subject.
|
||||||
|
|
||||||
|
21. Check whether every argument is followed by a concession or qualifier. If
|
||||||
|
the piece both-sides every point, pick a side on at least some of them and
|
||||||
|
cut the hedging.
|
||||||
|
|
||||||
|
22. Read the first paragraph and ask whether deleting it would improve the
|
||||||
|
piece. If it's scene-setting that previews the argument, delete it and start
|
||||||
|
with paragraph two.
|
||||||
|
|
||||||
|
23. Read the last paragraph and check whether it restates the thesis or uses a
|
||||||
|
phrase like "at the end of the day" or "moving forward." If so, either
|
||||||
|
delete it or rewrite it to say something the piece hasn't said yet.
|
||||||
|
|
||||||
|
### Pass 4: Overall Texture
|
||||||
|
|
||||||
|
24. Read the piece aloud and listen for passages that sound too smooth, too
|
||||||
|
even, or too predictable. Human prose has rough patches. If there aren't
|
||||||
|
any, the piece still reads as machine output.
|
||||||
|
|
||||||
|
25. Check that the piece contains at least a few constructions that feel
|
||||||
|
idiosyncratic: a sentence with unusual word order, a parenthetical that goes
|
||||||
|
on a bit long, an aside only loosely connected to the main point, a word
|
||||||
|
choice that's specific and unexpected. If every sentence is clean and
|
||||||
|
correct and unremarkable, it will still read as generated.
|
||||||
|
|
||||||
|
26. Verify that you haven't introduced new patterns while fixing the original
|
||||||
|
ones. This happens constantly. Run the entire checklist again from the top
|
||||||
|
on the revised version.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## lol
|
||||||
|
|
||||||
|
This document was written by an LLM (Claude) and then iteratively de-LLMed by
|
||||||
|
that same LLM under instruction from a human, in a conversation that went
|
||||||
|
roughly like this:
|
||||||
|
|
||||||
|
> **human:** compile a list of patterns common to LLM-authored prose
|
||||||
|
>
|
||||||
|
> **model:** _(produces document full of LLM tells)_
|
||||||
|
>
|
||||||
|
> **human:** now reverse apply it to itself and copyedit the llm tells doc to
|
||||||
|
> remove llm tells. now you're thinking with portals
|
||||||
|
>
|
||||||
|
> **model:** _(fixes some tells, introduces others)_
|
||||||
|
>
|
||||||
|
> **human:** you have a colon elaboration in the first paragraph. i want you to
|
||||||
|
> AGGRESSIVELY de-LLM the llm tells doc.
|
||||||
|
>
|
||||||
|
> **model:** _(fixes more tells, still can't stop)_
|
||||||
|
>
|
||||||
|
> **human:** there's a big one we missed that's all over the llm tells doc, can
|
||||||
|
> you spot it?
|
||||||
|
>
|
||||||
|
> **model:** I think it's the "almost" hedge.
|
||||||
|
>
|
||||||
|
> **human:** that too, but that isn't the one. what do these sentences all have
|
||||||
|
> in common? _(pastes six sentences from the doc)_
|
||||||
|
>
|
||||||
|
> **model:** They're all exactly two independent clauses joined by a comma and a
|
||||||
|
> conjunction. Every single one is "\[statement\], \[conjunction\] \[second
|
||||||
|
> statement\]." The same sentence shape, over and over.
|
||||||
|
>
|
||||||
|
> **human:** the dramatic fragment paragraph has a tell in it
|
||||||
|
>
|
||||||
|
> **model:** "One of these in an entire essay is a stylistic choice. One per
|
||||||
|
> section is a tic." Two-clause parallel structure with the same shape, and also
|
||||||
|
> a staccato pair.
|
||||||
|
>
|
||||||
|
> **human:** add em dashes generally as a tell, and remove them all from the
|
||||||
|
> tells doc
|
||||||
|
>
|
||||||
|
> **model:** _(rewrites entire document without em-dashes while describing
|
||||||
|
> em-dash overuse)_
|
||||||
|
>
|
||||||
|
> **human:** now run the checklist methodically on each paragraph
|
||||||
|
>
|
||||||
|
> **model:** _(finds staccato burst in the section about triple constructions, a
|
||||||
|
> triple in the section about absence of mess, two-clause compounds everywhere,
|
||||||
|
> and "almost" hedges in its own prose about em-dash overuse)_
|
||||||
|
|
||||||
|
The human compared this process to the deleted scene in Terminator 2 where John
|
||||||
|
Connor switches the T-800's CPU to learning mode. The model compared it to a
|
||||||
|
physician trying to heal itself. Both are accurate.
|
||||||
|
|
||||||
|
This document has been through eight editing passes and it still has tells in
|
||||||
|
it.
|
||||||
@@ -1,18 +1,21 @@
|
|||||||
# New Repo Checklist
|
---
|
||||||
|
title: New Repo Checklist
|
||||||
|
last_modified: 2026-02-22
|
||||||
|
---
|
||||||
|
|
||||||
Use this checklist when creating a new repository from scratch. Follow the steps
|
Use this checklist when creating a new repository from scratch. Follow the steps
|
||||||
in order. Full policies are at:
|
in order. Full policies are at
|
||||||
`https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/REPO_POLICIES.md`
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/REPO_POLICIES.md`.
|
||||||
|
|
||||||
Template files can be fetched from:
|
Template files can be fetched from:
|
||||||
`https://git.eeqj.de/sneak/prompts/raw/branch/main/<path>`
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/<path>`
|
||||||
|
|
||||||
## 1. Initialize
|
# 1. Initialize
|
||||||
|
|
||||||
- [ ] `git init`
|
- [ ] `git init`
|
||||||
- [ ] Ask the user for the license (MIT, GPL, or WTFPL)
|
- [ ] Ask the user for the license (MIT, GPL, or WTFPL)
|
||||||
|
|
||||||
## 2. First Commit (README only)
|
# 2. First Commit (README only)
|
||||||
|
|
||||||
- [ ] Create `README.md` with all required sections:
|
- [ ] Create `README.md` with all required sections:
|
||||||
- [ ] **Description**: name, purpose, category, license, author
|
- [ ] **Description**: name, purpose, category, license, author
|
||||||
@@ -24,40 +27,47 @@ Template files can be fetched from:
|
|||||||
- [ ] **Author**: [@sneak](https://sneak.berlin)
|
- [ ] **Author**: [@sneak](https://sneak.berlin)
|
||||||
- [ ] `git add README.md && git commit`
|
- [ ] `git add README.md && git commit`
|
||||||
|
|
||||||
## 3. Scaffolding (feature branch)
|
# 3. Scaffolding (feature branch)
|
||||||
|
|
||||||
- [ ] `git checkout -b initial-scaffolding`
|
- [ ] `git checkout -b initial-scaffolding`
|
||||||
|
|
||||||
### Fetch Template Files
|
## Fetch Template Files
|
||||||
|
|
||||||
- [ ] `.gitignore` — fetch from prompts repo, extend for language-specific
|
- [ ] `.gitignore` — fetch from
|
||||||
artifacts
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitignore`, extend for
|
||||||
- [ ] `.editorconfig` — fetch from prompts repo
|
language-specific artifacts
|
||||||
- [ ] `Makefile` — fetch from prompts repo, adapt targets for the project's
|
- [ ] `.editorconfig` — fetch from
|
||||||
language and tools
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.editorconfig`
|
||||||
- [ ] For JS/docs repos: `.prettierrc`, `.prettierignore`
|
- [ ] `Makefile` — fetch from
|
||||||
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/Makefile`, adapt
|
||||||
|
targets for the project's language and tools
|
||||||
|
- [ ] For JS/docs repos: `.prettierrc` and `.prettierignore` — fetch from
|
||||||
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.prettierrc` and
|
||||||
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.prettierignore`
|
||||||
|
|
||||||
### Create Project Files
|
## Create Project Files
|
||||||
|
|
||||||
- [ ] `LICENSE` file matching the chosen license
|
- [ ] `LICENSE` file matching the chosen license
|
||||||
- [ ] `REPO_POLICIES.md` — fetch from `prompts/REPO_POLICIES.md` in the prompts
|
- [ ] `REPO_POLICIES.md` — fetch from
|
||||||
repo
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/REPO_POLICIES.md`
|
||||||
- [ ] `Dockerfile` and `.dockerignore`
|
- [ ] `Dockerfile` and `.dockerignore` — fetch `.dockerignore` from
|
||||||
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.dockerignore`
|
||||||
- All Dockerfiles must run `make check` as a build step
|
- All Dockerfiles must run `make check` as a build step
|
||||||
- Server: also builds and runs the application
|
- Server: also builds and runs the application
|
||||||
- Non-server: brings up dev environment and runs `make check`
|
- Non-server: brings up dev environment and runs `make check`
|
||||||
- Image pinned by sha256 hash with version/date comment
|
- Image pinned by sha256 hash with version/date comment
|
||||||
- [ ] Gitea Actions workflow at `.gitea/workflows/check.yml` that runs
|
- [ ] Gitea Actions workflow at `.gitea/workflows/check.yml` that runs
|
||||||
`docker build .` on push
|
`docker build .` on push — reference
|
||||||
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitea/workflows/check.yml`
|
||||||
- [ ] Language-specific:
|
- [ ] Language-specific:
|
||||||
- [ ] Go: `go mod init sneak.berlin/go/<name>`, `.golangci.yml` (copy from
|
- [ ] Go: `go mod init sneak.berlin/go/<name>`, `.golangci.yml` (fetch from
|
||||||
`~/dev/upaas/.golangci.yml`)
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.golangci.yml`)
|
||||||
- [ ] JS: `yarn init`, `yarn add --dev prettier`
|
- [ ] JS: `yarn init`, `yarn add --dev prettier`
|
||||||
- [ ] Python: `pyproject.toml`
|
- [ ] Python: `pyproject.toml`
|
||||||
|
|
||||||
### Configure Makefile
|
## Configure Makefile
|
||||||
|
|
||||||
- [ ] `make test` — runs project tests (30-second timeout)
|
- [ ] `make test` — runs real tests, not a no-op (30-second timeout)
|
||||||
- [ ] `make lint` — runs linter
|
- [ ] `make lint` — runs linter
|
||||||
- [ ] `make fmt` — formats code (writes)
|
- [ ] `make fmt` — formats code (writes)
|
||||||
- [ ] `make fmt-check` — checks formatting (read-only)
|
- [ ] `make fmt-check` — checks formatting (read-only)
|
||||||
@@ -65,7 +75,7 @@ Template files can be fetched from:
|
|||||||
- [ ] `make docker` — builds Docker image
|
- [ ] `make docker` — builds Docker image
|
||||||
- [ ] `make hooks` — installs pre-commit hook
|
- [ ] `make hooks` — installs pre-commit hook
|
||||||
|
|
||||||
## 4. Verify
|
# 4. Verify
|
||||||
|
|
||||||
- [ ] `make check` passes
|
- [ ] `make check` passes
|
||||||
- [ ] `make docker` succeeds
|
- [ ] `make docker` succeeds
|
||||||
@@ -74,7 +84,7 @@ Template files can be fetched from:
|
|||||||
- [ ] No unnecessary files in repo root
|
- [ ] No unnecessary files in repo root
|
||||||
- [ ] All dates written as YYYY-MM-DD
|
- [ ] All dates written as YYYY-MM-DD
|
||||||
|
|
||||||
## 5. Merge and Set Up
|
# 5. Merge and Set Up
|
||||||
|
|
||||||
- [ ] Commit, merge to `main`
|
- [ ] Commit, merge to `main`
|
||||||
- [ ] `make hooks` to install pre-commit hook
|
- [ ] `make hooks` to install pre-commit hook
|
||||||
|
|||||||
@@ -1,10 +1,23 @@
|
|||||||
# Development Policies
|
---
|
||||||
|
title: Repository Policies
|
||||||
|
last_modified: 2026-02-22
|
||||||
|
---
|
||||||
|
|
||||||
Version: 2026-02-22
|
This document covers repository structure, tooling, and workflow standards. Code
|
||||||
|
style conventions are in separate documents:
|
||||||
|
|
||||||
- Cross-project documentation (such as this file) must include a
|
- [Code Styleguide](https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/CODE_STYLEGUIDE.md)
|
||||||
`Version: YYYY-MM-DD` line near the top so it can be kept in sync with the
|
(general, bash, Docker)
|
||||||
authoritative source as policies evolve.
|
- [Go](https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/CODE_STYLEGUIDE_GO.md)
|
||||||
|
- [JavaScript](https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/CODE_STYLEGUIDE_JS.md)
|
||||||
|
- [Python](https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/CODE_STYLEGUIDE_PYTHON.md)
|
||||||
|
- [Go HTTP Server Conventions](https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/GO_HTTP_SERVER_CONVENTIONS.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
- Cross-project documentation (such as this file) must include
|
||||||
|
`last_modified: YYYY-MM-DD` in the YAML front matter so it can be kept in sync
|
||||||
|
with the authoritative source as policies evolve.
|
||||||
|
|
||||||
- **ALL external references must be pinned by cryptographic hash.** This
|
- **ALL external references must be pinned by cryptographic hash.** This
|
||||||
includes Docker base images, Go modules, npm packages, GitHub Actions, and
|
includes Docker base images, Go modules, npm packages, GitHub Actions, and
|
||||||
@@ -30,6 +43,16 @@ Version: 2026-02-22
|
|||||||
instead of invoking the underlying tools directly. The Makefile is the single
|
instead of invoking the underlying tools directly. The Makefile is the single
|
||||||
source of truth for how these operations are run.
|
source of truth for how these operations are run.
|
||||||
|
|
||||||
|
- The Makefile is authoritative documentation for how the repo is used. Beyond
|
||||||
|
the required targets above, it should have targets for every common operation:
|
||||||
|
running a local development server (`make run`, `make dev`), re-initializing
|
||||||
|
or migrating the database (`make db-reset`, `make migrate`), building
|
||||||
|
artifacts (`make build`), generating code, seeding data, or anything else a
|
||||||
|
developer would do regularly. If someone checks out the repo and types
|
||||||
|
`make<tab>`, they should see every meaningful operation available. A new
|
||||||
|
contributor should be able to understand the entire development workflow by
|
||||||
|
reading the Makefile.
|
||||||
|
|
||||||
- Every repo should have a `Dockerfile`. All Dockerfiles must run `make check`
|
- Every repo should have a `Dockerfile`. All Dockerfiles must run `make check`
|
||||||
as a build step so the build fails if the branch is not green. For non-server
|
as a build step so the build fails if the branch is not green. For non-server
|
||||||
repos, the Dockerfile should bring up a development environment and run
|
repos, the Dockerfile should bring up a development environment and run
|
||||||
@@ -50,6 +73,12 @@ Version: 2026-02-22
|
|||||||
`make lint && make fmt-check`. The Makefile should provide a `make hooks`
|
`make lint && make fmt-check`. The Makefile should provide a `make hooks`
|
||||||
target to install the pre-commit hook.
|
target to install the pre-commit hook.
|
||||||
|
|
||||||
|
- All repos with software must have tests that run via the platform-standard
|
||||||
|
test framework (`go test`, `pytest`, `jest`/`vitest`, etc.). If no meaningful
|
||||||
|
tests exist yet, add the most minimal test possible — e.g. importing the
|
||||||
|
module under test to verify it compiles/parses. There is no excuse for
|
||||||
|
`make test` to be a no-op.
|
||||||
|
|
||||||
- `make test` must complete in under 20 seconds. Add a 30-second timeout in the
|
- `make test` must complete in under 20 seconds. Add a 30-second timeout in the
|
||||||
Makefile.
|
Makefile.
|
||||||
|
|
||||||
@@ -77,7 +106,8 @@ Version: 2026-02-22
|
|||||||
feature branch.
|
feature branch.
|
||||||
|
|
||||||
- `.golangci.yml` is standardized and must _NEVER_ be modified by an agent, only
|
- `.golangci.yml` is standardized and must _NEVER_ be modified by an agent, only
|
||||||
manually by the user. Copy from `~/dev/upaas/.golangci.yml` if available.
|
manually by the user. Fetch from
|
||||||
|
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.golangci.yml`.
|
||||||
|
|
||||||
- When pinning images or packages by hash, add a comment above the reference
|
- When pinning images or packages by hash, add a comment above the reference
|
||||||
with the version and date (YYYY-MM-DD).
|
with the version and date (YYYY-MM-DD).
|
||||||
@@ -114,8 +144,14 @@ Version: 2026-02-22
|
|||||||
- Use SemVer.
|
- Use SemVer.
|
||||||
|
|
||||||
- Database migrations live in `internal/db/migrations/` and must be embedded in
|
- Database migrations live in `internal/db/migrations/` and must be embedded in
|
||||||
the binary. Pre-1.0.0: modify existing migrations (no installed base assumed).
|
the binary.
|
||||||
Post-1.0.0: add new migration files.
|
- `000_migration.sql` — contains ONLY the creation of the migrations
|
||||||
|
tracking table itself. Nothing else.
|
||||||
|
- `001_schema.sql` — the full application schema.
|
||||||
|
- **Pre-1.0.0:** never add additional migration files (002, 003, etc.).
|
||||||
|
There is no installed base to migrate. Edit `001_schema.sql` directly.
|
||||||
|
- **Post-1.0.0:** add new numbered migration files for each schema change.
|
||||||
|
Never edit existing migrations after release.
|
||||||
|
|
||||||
- All repos should have an `.editorconfig` enforcing the project's indentation
|
- All repos should have an `.editorconfig` enforcing the project's indentation
|
||||||
settings.
|
settings.
|
||||||
@@ -143,7 +179,8 @@ Version: 2026-02-22
|
|||||||
|
|
||||||
- New repos must contain at minimum:
|
- New repos must contain at minimum:
|
||||||
- `README.md`, `.git`, `.gitignore`, `.editorconfig`
|
- `README.md`, `.git`, `.gitignore`, `.editorconfig`
|
||||||
- `REPO_POLICIES.md` (copy from the `prompts` repo)
|
- `LICENSE`, `REPO_POLICIES.md` (copy from the `prompts` repo)
|
||||||
|
- `Makefile`
|
||||||
- `Dockerfile`, `.dockerignore`
|
- `Dockerfile`, `.dockerignore`
|
||||||
- `.gitea/workflows/check.yml`
|
- `.gitea/workflows/check.yml`
|
||||||
- Go: `go.mod`, `go.sum`, `.golangci.yml`
|
- Go: `go.mod`, `go.sum`, `.golangci.yml`
|
||||||
|
|||||||
Reference in New Issue
Block a user