
Blog-Writer
A self-contained opencode automation project that turns recent work across your other projects into bilingual (English + Italian) MDX blog articles, observing sources read-only and publishing only on explicit command.
Type: Product
Status: Completed
Date: 7/27/2026
- opencode
- Git
- SQLite
- MDX
- Bash
- Next.js
- Tailwind CSS
Overview
Blog-Writer is a self-contained opencode project that turns recent work — spread across several other projects — into bilingual (English + Italian) blog articles for a Tailwind/Next.js MDX blog. Its defining principle is restraint: it only observes the projects it writes about and never modifies them. Two manually-invoked agents live inside the project, and every capability they have is bounded by an explicit, auditable permission model.
Unlike generic "AI writing assistant" tooling, Blog-Writer is purpose-built around a real content pipeline: it mines your own git history and opencode session transcripts for genuine, recently-completed work, proposes scored candidate topics, drafts an article with you in the loop, and publishes only when you explicitly say so. It is a disciplined authoring companion rather than an autonomous content generator.
Motivation
Developers accumulate a steady stream of interesting work — bug hunts, architecture decisions, tricky refactors — but the gap between "did the work" and "wrote about it" is where most blog posts die. Existing solutions fell short:
- Generic AI writers invent plausible-sounding content untethered from what you actually did
- Manual blogging requires remembering, reconstructing, and translating work weeks after the fact
- Automation tools often demand broad, uncomfortable access to source repositories and secrets
- Single-language workflows make maintaining synchronized bilingual content tedious and error-prone
Blog-Writer was conceived to bridge these gaps by creating a system that:
- Grounds articles in real evidence: Topics are surfaced from actual git commits and opencode session transcripts, correlated by timestamp, never invented
- Keeps the human in control: Nothing is drafted, published, or committed without an explicit instruction
- Observes without touching: Source projects are read-only inputs; the tool never edits, commits, or pushes to them
- Produces bilingual output natively: English and Italian are first-class from the start, assembled into a single MDX file
- Respects privacy and safety: A strict permission boundary denies destructive commands and blocks well-known secret stores
The goal was a tool that quietly lowers the activation energy for writing about your work — without ever putting your repositories, secrets, or published output at risk.
System Architecture
Blog-Writer is built as an opencode project with a deliberately small surface area, organized around two agents, a directory-based workflow, and a declarative permission boundary:
Two Manually-Invoked Agents The project ships with
topic-extractor(a read-only analyst) andblog-writer(a drafting and publishing agent). There is no automation or scheduling — each agent is invoked deliberately by the user from inside the project. This keeps the human firmly in the loop at every stage.Evidence-Gathering Pipeline The
topic-extractorreads git commit history and opencode session transcripts directly from the session database usingsqlite3 -readonly, filtering on thetime_updatedcolumn. It correlates commits and transcripts by timestamp to reconstruct what actually happened during a given window, and redacts obvious secrets before anything reaches a candidate file.Directory-Based Workflow Content flows through a clear filesystem pipeline:
inputs/holds candidate-topic files (topics-YYYY-MM-DD.md) plus apublished-topics.mdledger;drafts/holds in-progress articles markeddraft: true; andpublished/holds finished articles moved there only on explicit command. Each stage is inspectable and version-controllable.Scoring and De-duplication Each candidate topic is scored across five dimensions — Reader appeal, Technical depth, Storytelling, Uniqueness, and Publishability — and ordered by an Overall score. Topics you have already published (matched by a stable
topic_keyvia thepublished-topics.mdledger and published frontmatter) are skipped, so re-running the extractor never resurfaces finished work. Drafts do not count — only published articles.Optional Allowlist A
tracked-projects.txtfile acts as an optional allowlist: when present and non-empty, only the listed project directories are considered; when absent or comment-only, the extractor auto-discovers candidate projects from the opencode database and confirms the list with you before extracting. This makes it trivial to exclude sensitive projects.Declarative Permission Boundary The entire safety model lives in
.opencode/opencode.json. Both agents may read anywhere (to inspect sources and the database), but edits are tightly scoped per agent, and destructive commands are denied outright. Permission rules are resolved by last-matching-rule-wins ordering, with a catch-all placed first and narrow rules after it.
Key Features
Read-Only Topic Extraction The topic-extractor is a pure analyst. Ask it to "extract topics from last week" and it determines which projects to consider, reads git history and opencode transcripts via sqlite3 -readonly, correlates them by timestamp, redacts obvious secrets, scores the candidates, and writes a DRAFT topics file named by the run date (so same-week re-runs don't collide) — recording the ISO week, window, and a generation timestamp inside. On your approval it flips Status: DRAFT to Status: FINAL. It never writes an article itself.
Human-in-the-Loop Drafting The blog-writer agent reads your CONVENTIONS.md (your writing voice and style), drafts the English body first, and iterates with you until it's right. Only then does it translate to Italian and assemble a single bilingual drafts/<slug>.mdx with draft: true frontmatter and a stable topic_key. Every step is collaborative and reversible.
Explicit-Command Publishing Publishing is never implicit. On your explicit "publish <slug>" command, the blog-writer flips draft: false, moves the file to published/<slug>.mdx, and records the topic_key in inputs/published-topics.md so the extractor won't resurface it. It never edits source projects and never commits or pushes.
Observe-Only Guarantee The most important feature is a non-feature: Blog-Writer cannot modify the projects it writes about. They are strictly read-only inputs. This guarantee is enforced structurally through the permission boundary, not merely by convention.
Enforced Permission Model Both agents may read anywhere and may run git * and sqlite3 * -readonly *, but git push, git commit --amend, and rm -rf are denied. The topic-extractor may edit only within inputs/**; the blog-writer may edit only within drafts/**, inputs/**, and published/**. An external_directory policy allows reading under the home directory and the opencode DB directory while denying well-known secret stores (~/.ssh, ~/.aws, ~/.gnupg, ~/.config, and any .env).
Repeatable Acceptance Testing A single end-to-end acceptance procedure maps every acceptance criterion to a concrete check, distinguishing automated mechanical verifiers from the manual agent-conversation script. The whole mechanical suite runs from the project root via bash tests/run_all.sh, with individual verifiers for scaffolding, topic extraction, conventions, drafting, system-wide checks, permission denial, and deterministic redaction. The permission and destructive-command scenarios can additionally be proven against the live runtime as an opt-in check.
Technical Excellence
The project demonstrates several thoughtful engineering practices:
- Least-Privilege Design: Every agent capability is the minimum required; broad reads are allowed, but writes and destructive commands are tightly constrained
- Deterministic Verification: Redaction and flagging logic are covered by deterministic tests, so safety behavior is provable rather than assumed
- Read-Only Data Access: The opencode session database is always opened with
sqlite3 -readonly, guaranteeing the analysis pipeline can never mutate source data - Idempotent Re-runs: The
topic_keyledger makes re-running the extractor safe — finished work is never resurfaced - Timestamp Correlation: Commits and session transcripts are joined by time to reconstruct an accurate picture of a work window
- Configuration Discipline: The permission config's rule ordering is documented and intentional, acknowledging that opencode resolves patterns by last-match-wins
Privacy & Security
Blog-Writer treats safety as a first-class architectural concern:
- No source modification: Projects being written about are read-only; the tool cannot edit, commit, or push to them
- No destructive commands:
git push,git commit --amend, andrm -rfare denied at the permission layer - Secret-store denial:
~/.ssh,~/.aws,~/.gnupg,~/.config, and any.envfiles are explicitly off-limits - Read-only database access: The opencode session DB is only ever opened with
sqlite3 -readonly - Secret redaction: Obvious secrets are redacted before candidate content is written
- Scoped writes: Each agent can only write within the specific directories its role requires
- No automation: Nothing runs on a schedule; every action is a deliberate, human-initiated invocation
Development Philosophy
The project reflects a disciplined, safety-first approach to agentic tooling:
- Restraint by Default: The tool does as little as possible to sources — observing, never touching
- Human in the Loop: Drafting and publishing always require explicit human instruction
- Evidence over Invention: Articles are grounded in real git and session history, not fabricated
- Provable Safety: Permission boundaries and redaction are tested, not merely asserted
- Transparency: Every stage produces inspectable, version-controllable artifacts on disk
- Bilingualism as Standard: English and Italian are produced together, keeping translations synchronized
Impact
Blog-Writer demonstrates how agentic automation can be genuinely useful without being reckless. By grounding topics in real work, keeping the human in control of every draft and publish, and enforcing a strict observe-only permission boundary, it turns the tedious "I should write about that" impulse into a low-friction, repeatable pipeline — while guaranteeing that the projects being written about are never put at risk.
The scoring-and-ledger design means the tool respects your time: it surfaces only fresh, unpublished topics and orders them by genuine editorial value. The bilingual-by-default output removes the translation tax that usually discourages maintaining a dual-language blog. And because the whole safety model is declarative and tested, the tool can be trusted to run against real repositories and a real session database without anxiety.
Future Directions
Potential enhancements under consideration include:
- Additional scoring dimensions and configurable weightings tuned to personal editorial taste
- Richer redaction heuristics and per-project redaction rules
- Support for additional target languages beyond English and Italian
- Optional integration with more source signals (issue trackers, PR discussions)
- A summary dashboard of published topics and coverage gaps across projects
- Draft revision history and side-by-side bilingual review tooling
Blog-Writer represents a complete, safety-conscious agentic tool that successfully merges evidence-based topic discovery, human-in-the-loop authoring, and native bilingual output into a workflow that respects both your time and your repositories.