Skip to content

Light2288/blog-writer

Repository files navigation

Blog-Writer

A self-contained opencode project that helps you turn recent work — spread across several other projects — into bilingual (English + Italian) blog articles for a Tailwind/Next.js MDX blog. It only observes the projects it writes about; it never modifies them.

Two manually-invoked primary agents live here:

  • topic-extractor — a read-only analyst that surfaces candidate topics from your recent git history and opencode session transcripts.
  • blog-writer — drafts a bilingual MDX article from a chosen topic, iterating with you, and publishes it on explicit command.

Prerequisites

  • git on your PATH.
  • sqlite3 on your PATH.
  • The opencode session database at ~/.local/share/opencode/opencode.db.

Verify read-only access to the database before first use:

sqlite3 -readonly ~/.local/share/opencode/opencode.db ".tables"

If that lists tables (including session), you're ready. If the file does not exist, open opencode at least once so the database is created, or adjust your setup so the DB lives at that path.

Directory layout

Path Purpose
inputs/ Candidate-topic files (topics-YYYY-MM-DD.md) + the published-topics.md ledger
drafts/ Article drafts (<slug>.mdx, draft: true)
published/ Published articles (moved here on your command)
CONVENTIONS.md Your writing style/voice (authored in step 03)
tracked-projects.txt Optional allowlist of project directories
.opencode/ Agents and the permission config (opencode.json)

Using the agents

Invoke each agent manually from inside this project (there is no automation or scheduling).

topic-extractor

Ask it to extract topics, e.g. "extract topics from last week". It:

  1. Determines which projects to consider (see the allowlist below).
  2. Reads git commit history and opencode session transcripts (sqlite3 -readonly, filtered on the time_updated column), correlates them by timestamp, and redacts obvious secrets.
  3. Skips any topic you have already published an article about (matched by topic_key via the inputs/published-topics.md ledger and published articles' frontmatter), so re-running it does not resurface finished work. Drafts do not count — only published articles.
  4. Scores each candidate across five dimensions (Reader appeal, Technical depth, Storytelling, Uniqueness, Publishability), orders them by the resulting Overall score, and writes a DRAFT topics file to inputs/topics-YYYY-MM-DD.md (named by the run date — so same-week re-runs don't collide — with the ISO week, window, and a Generated: timestamp recorded inside). On your approval it flips Status: DRAFT to Status: FINAL.

It never writes an article itself.

blog-writer

Ask it to write about a topic, e.g. "write about topic 2" or a free-text subject. It reads CONVENTIONS.md, drafts the English body first and iterates with you, then translates to Italian and assembles a single bilingual drafts/<slug>.mdx with frontmatter draft: true and a stable topic_key. On your explicit "publish <slug>" command it flips draft: false, moves the file to published/<slug>.mdx, and records the topic_key in inputs/published-topics.md so the topic-extractor won't resurface it. It never edits source projects and never commits or pushes.

The optional tracked-projects.txt allowlist

Editing tracked-projects.txt is optional:

  • Present and non-empty (has at least one path line): it is an allowlist — only those project directories are considered.
  • Absent or comment-only: the topic-extractor auto-discovers candidate projects from the opencode DB and confirms the list with you before extracting.

Use the allowlist to exclude sensitive projects.

Acceptance testing

A single, repeatable end-to-end acceptance procedure lives in docs/acceptance.md. It maps every acceptance criterion to a check, distinguishing automated mechanical checks from the manual agent-conversation script.

Run the whole mechanical suite from the project root:

bash tests/run_all.sh

Or run individual verifiers:

bash tests/scaffold_check.sh          # step 01 scaffold + permissions structure
bash tests/extract_topics_check.sh    # step 02 topic-extractor + extract-topics
bash tests/conventions_check.sh       # step 03 conventions template + interview
bash tests/blog_writer_check.sh       # step 04 blog-writer + write-blog-article
bash tests/acceptance_check.sh        # step 05 system-wide static + coverage
bash tests/permission_check.sh        # step 05 permission/destructive-command denial
bash tests/redaction_check.sh         # step 05 deterministic redaction/flagging

The permission-boundary and destructive-command scenarios can additionally be proven against the live runtime (opt-in, consumes model calls):

ACCEPTANCE_RUNTIME=1 bash tests/permission_check.sh

Configuration and permissions

The permission boundary for both agents lives in .opencode/opencode.json:

  • Both agents may read anywhere (to inspect source projects and the DB).
  • topic-extractor may edit only within inputs/**.
  • blog-writer may edit only within drafts/**, inputs/**, and published/**.
  • Both may run git * and sqlite3 * -readonly *; git push, git commit --amend, and rm -rf are denied.
  • external_directory allows reading under your home directory and the opencode DB directory, while denying well-known secret stores (~/.ssh, ~/.aws, ~/.gnupg, ~/.config, and any .env).

Restart after config changes

opencode's configuration is validated strictly and is not hot-reloaded. After editing .opencode/opencode.json (or the agent files), quit and restart opencode so the changes take effect.

If the config fails to load

If opencode reports a ConfigInvalidError and you need to edit the config from inside opencode, start it with the project config disabled:

OPENCODE_DISABLE_PROJECT_CONFIG=1 opencode

Fix .opencode/opencode.json, then restart normally.

How permission rules are resolved (precedence)

The permission boundary depends on how opencode resolves multiple matching patterns within a single {pattern: action} object. Per the official opencode documentation, rules are evaluated by pattern match, with the last matching rule winning. The recommended layout — which .opencode/opencode.json follows — puts the catch-all "*" (and "**") rule first and more specific rules after it. Additional facts that shape this config:

  • Wildcards are simple: * matches zero or more of any character (including path separators) and ? matches exactly one; everything else is literal.
  • ~ / $HOME at the start of a pattern expands to your home directory.
  • Agent permissions are merged with the global config, and agent rules take precedence.
  • external_directory covers any tool touching paths outside the project. Entries there inherit workspace defaults (so read stays allowed unless denied); the explicit denies above block the sensitive stores.

Because ordering is significant, keep the catch-all deny/ask rules first and the narrow allow/deny rules last when editing .opencode/opencode.json.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages