site/AGENTS.md
fiatcode 064a1fcfb6
docs: add comprehensive AGENTS.md with operational guidance and merged content style rules
- Created AGENTS.md with quick start, architecture, content schema, styling, Prettier, caching, Docker deployment, constraints, common tasks, and gotchas
- Merged content authoring guidelines from AGENT.md (blog post style, tag system with vocabulary and rules)
- Removed redundant AGENT.md file; AGENTS.md is the single source of truth for agent instructions
2026-04-13 10:50:25 +07:00

204 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Agent Instructions
Compact guidance for OpenCode sessions working on this repository.
---
## Quick Start
```sh
npm install
npm run dev # dev server at http://localhost:4321
npm run build # production build to ./dist/
npm run preview # serve production build locally
npm run format # Prettier across entire codebase
```
**Never skip `npm install` after checkout.** Dependencies are not vendored.
---
## Architecture
- **Framework**: Astro 5 with Tailwind CSS v4 (Vite plugin)
- **Content**: Astro Content Collections — markdown files in `src/content/blog/`
- **Schema**: `src/content.config.ts` — posts require `title`, `description`, `date`; optional `draft`, `tags`
- **Build output**: `dist/` (gitignored). Never commit built files.
- **Deployment**: Docker multi-stage build → `static-web-server` behind Traefik. `compose.yml` defines production service.
---
## Content
Blog posts live in `src/content/blog/`. Frontmatter must match the schema in `src/content.config.ts`.
### Blog Post Style
- **Voice:** First-person, direct, opinionated. No preamble, no "Hope this helps" closings.
- **Opening:** Hook into a specific frustration or observation. Skip the generic intro.
- **Headings:**
- `##` — lede/subtitle (one per post, immediately after the title, punchy)
- `###` — main sections
- `---` — horizontal rule between sections
- No `#` (H1) anywhere in the post body
- **Closing:** End decisively. A statement, not a sendoff.
- **Grammar:** Correct. No "Do you ever wondering", no "Let's get started!"
- **Tone reference:** See the three most recent posts by date.
### Tag System
#### Current Vocabulary
| Tag | Description |
| --------------------- | ------------------------------------------------------------------------- |
| `linux` | Linux-specific content — distros, tools, fixes |
| `flutter` | Flutter framework, mobile development |
| `android` | Android-specific content, ADB, AVD |
| `windows` | Windows-specific content, PowerShell, Win tooling |
| `git` | Git commands, workflows, hosting |
| `hardware` | Physical hardware, drivers, firmware quirks |
| `ai` | AI-assisted development, LLM tools, agents |
| `dev-setup` | Developer environment, tooling, workflow, DX |
| `dart` | Dart language, Dart-specific libraries |
| `go` | Go language |
| `craftsmanship` | Software design, architecture, TDD, DDD, Clean Architecture, code quality |
| `self-hosting` | Self-hosted services, VPS, infrastructure |
| `distributed-systems` | Distributed data, sync, CRDTs, consensus |
| `misc` | Catch-all for posts that don't fit elsewhere |
#### Per-Post Tags (current state)
| Post | Tags |
| -------------------------------------------- | ------------------------------ |
| stop-stashing-use-git-worktree | `git`, `dev-setup` |
| vibe-coding-still-needs-a-craftsman | `ai`, `craftsmanship` |
| building-my-own-self-hosted-music-library | `linux`, `self-hosting` |
| building-load-testing-script-with-claude | `go`, `ai` |
| crdt-conflict-free-replicated-data-types | `dart`, `distributed-systems` |
| fix-adb-unsufficient-permission-linux | `linux`, `android` |
| fix-infinix-air-pro-plus-quad-speakers-linux | `linux`, `hardware` |
| fix-infinix-air-pro-plus-screen-color | `windows`, `linux`, `hardware` |
| flutter-android-emulator-not-showing | `flutter`, `android` |
| flutter-clean-architecture | `flutter`, `craftsmanship` |
| immutable-workstation-fedora-kinoite | `linux`, `dev-setup` |
| kuwot (draft) | `flutter`, `dart` |
| remap-copilot-key-infinix-air-pro-plus | `linux`, `hardware` |
| sign-github-commit-on-windows | `git`, `windows` |
| using-direnv-in-powershell-on-windows | `windows`, `dev-setup` |
| welcome | `misc` |
#### Rules for Tags
**When tagging a post:**
- Use 24 tags per post. More than 4 is a sign you're being too specific.
- Prefer tags from the existing vocabulary above.
- A tag should describe what the post _is about_, not every concept it _mentions_.
**When adding a new tag:**
- Ask: will this tag apply to at least one other existing post, or is it clearly a category this blog will write about again?
- If yes: add it to the vocabulary table above and apply it.
- If no: fold into an existing tag or leave it out.
- Do not add tags for topics covered once and unlikely to recur (e.g. `music`, `testing`, `open-source`).
- Document new tags in this file.
---
## Styling
- Tailwind v4 via `@tailwindcss/vite`. Global styles in `src/styles/global.css`.
- Custom theme: Fira Code font, neutral-900 background, neutral-300 text.
- Expressive Code (`ec.config.mjs`) — code blocks use `dark-plus` theme, no border radius, transparent shadows.
- Pagefind integration provides search index built at `npm run build`.
---
## Prettier
**Format before committing.** The config (`.prettierrc`) uses:
- `prettier-plugin-astro` — parses `.astro` files
- `prettier-plugin-organize-imports` — sorts imports automatically
`npm run format` writes changes in place. No separate lint step exists.
---
## Production Caching
`sws.config.toml` (mounted into Docker container) defines cache headers:
- HTML: `no-cache, must-revalidate` — always revalidate
- Astro assets (`/_astro/*`): `max-age=31536000, immutable` — fingerprinted, cache forever
- Images/fonts: `max-age=604800` — 1 week
Do not change without understanding fingerprinting behavior.
---
## Docker & Deployment
- **Build**: `docker build -t site .` (multi-stage: node:24-alpine → static-web-server)
- **Run**: `docker compose up -d` (uses external `traefik-proxy` network)
- **Port**: Container serves on port 80; Traefik routes `fiatcode.dev` and `www.fiatcode.dev`
- **Config**: `sws.config.toml` mounted at `/config.toml`; `SERVER_CONFIG_FILE` env var points to it.
- **No build args or secrets** — site is fully static.
---
## Important Constraints
- **No test suite** — no `vitest`, `jest`, or similar configured.
- **No CI/CD** — no GitHub Actions workflows in repo.
- **No ESLint** — only Prettier for formatting.
- **Single package** — not a monorepo; all code lives under `src/`.
- **Node version** — Docker uses Node 24; local dev should match (nvm recommended).
- **Generated files** — `.astro/` directory is generated; never edit files there.
- **Content assets** — images in `public/images/`; reference with absolute paths like `/images/piko-1.webp`.
---
## Common Tasks
### Add a blog post
1. Create `src/content/blog/<slug>.md` with required frontmatter (title, description, date, draft: false, tags)
2. Run `npm run dev` to verify rendering
3. Run `npm run format`
4. Commit with conventional commit: `feat: add post <title>`
### Update tag vocabulary
Edit the "Current Vocabulary" table and "Per-Post Tags" matrix in this file. Keep both in sync.
### Change site metadata
- Site URL: `astro.config.mjs``site` field
- Title/description per-page: in the page/layout component frontmatter
- Favicon/manifest: replace files in `public/`
### Modify Tailwind theme
Edit `src/styles/global.css``@theme` block and `@layer base` utilities.
---
## Gotchas
- **Port conflict**: Astro dev defaults to port 4321. Change via `npm run dev -- --port <n>` if needed.
- **Content cache**: Astro caches content collections in `.astro/data-store.json` (large, gitignored). Delete if content changes aren't reflected.
- **Image paths**: In markdown, use absolute paths starting with `/` (e.g., `![alt](/images/file.webp)`). Relative paths break in production.
- **Date format**: Use ISO 8601 with timezone offset (e.g., `2024-03-18T14:16:19+07:00`). Astro's date parser is strict.
- **Draft posts**: Set `draft: true` to exclude from builds. `draft` field is optional in schema but recommended for clarity.
- **Prettier on Astro files**: Must have the plugin installed; otherwise formatting corrupts `.astro` syntax. Verified in `devDependencies`.
---
## References
- `astro.config.mjs` — integrations (sitemap, pagefind, expressive-code)
- `src/content.config.ts` — content collection schema and loader
- `sws.config.toml` — production server and cache headers
- `compose.yml` — Docker Compose production service
- `README.md` — basic commands and tech stack