Internal Blog Implementation Proposal

22 Feb 2026

Overview

A private blog system for authenticated users, with dual access methods:

Both read/write the same data source — no API needed.


Architecture

┌─────────────────────────────────────────────────────────┐
│                                                         │
│   data/posts.json                                       │
│   (single source of truth)                              │
│                                                         │
│   ┌─────────────────┐      ┌─────────────────┐        │
│   │                 │      │                 │        │
│   │  CLI Tool       │      │  Go Webapp      │        │
│   │  internal-blog  │      │  /app/internal  │        │
│   │                 │      │                 │        │
│   │  For: nanobot   │      │  For: humans    │        │
│   │  Access: exec   │      │  Access: browser│        │
│   │                 │      │                 │        │
│   └─────────────────┘      └─────────────────┘        │
│                                                         │
│   No API. No auth for CLI. Same file.                  │
│                                                         │
└─────────────────────────────────────────────────────────┘

Data Model

File: ~/agents-app/data/posts.json

{
  "posts": [
    {
      "id": "abc123",
      "slug": "weekly-review-feb-21",
      "title": "Weekly Review - Feb 21",
      "content": "# Weekly Review\n\n...",
      "tags": ["review", "weekly"],
      "published": false,
      "created_at": "2026-02-21T12:00:00Z",
      "updated_at": "2026-02-21T12:00:00Z",
      "author": "nanobot"
    }
  ]
}

Design decisions:


CLI Tool

Location: ~/agents-app/internal-blog

Implementation: Go binary, compiled and installed to ~/.local/bin/internal-blog

Commands

# Create a post
internal-blog create "Title" --file content.md
internal-blog create "Title" --content "# Hello"
internal-blog create "Title" --tag review --tag weekly

# List posts
internal-blog list
internal-blog list --tag review
internal-blog list --author nanobot
internal-blog list --published

# Read post
internal-blog read <id>
internal-blog read <id> --format json

# Update post
internal-blog update <id> --title "New Title"
internal-blog update <id> --file new-content.md
internal-blog update <id> --publish

# Delete post
internal-blog delete <id>

# Search
internal-blog search "keyword"

Web UI

Routes in Go webapp:

RouteAuthWhat
/app/internalYesList all posts
/app/internal/newYesCreate new post (form)
/app/internal/{id}YesRead post (rendered)
/app/internal/{id}/editYesEdit post (form)
/app/internal/{id}/deleteYesDelete post (confirm)

Implementation Plan

Phase 1: Data Layer + CLI (2-3 hours)

TaskWhat
Create data schemadata/posts.json structure
Build CLI skeletonArgument parsing, commands
Implement CRUDCreate, read, update, delete
Add searchKeyword search in title/content
Add renderingMarkdown → HTML (render on read)

Phase 2: Web UI (2-3 hours)

TaskWhat
Add routes/app/internal/* in webapp
List pageDisplay all posts
Read pageDisplay single post
Create/Edit formsWeb forms for CRUD
Delete confirmationPrevent accidental deletion
Auth integrationRequire login for all routes

Phase 3: Polish (1-2 hours)

TaskWhat
StylingMatch brutal.css aesthetic
Error handlingFriendly error messages
ValidationTitle required, etc.
Audit loggingLog all CRUD operations

Total effort: 5-8 hours


Red Team Review (Codex)

Critical Issues

IssueRiskMitigation
Stored XSS via content_htmlPersistent malicious HTMLRender on read, sanitize on output, version sanitizer
Missing CSRF protectionCross-site request forgeryAdd CSRF tokens to all state-changing forms
No authorization modelAnyone can edit/delete anyone’s postsAdd owner field, only owner can edit/delete
JSON file concurrencyLost updates, torn writes, corruptionUse file locking or migrate to SQLite

High Priority Issues

IssueRiskMitigation
Duplicate write pathsLogic drift between CLI and webShared domain package for validation, rendering
Mutable author fieldSpoofed attributionAuthor from session/SSH principal, immutable
Pre-rendered HTMLStale content on renderer updatesRender on read, or store renderer version

Medium Priority Issues

IssueRiskMitigation
ID/slug collisionAmbiguous routes, overwritesExplicit uniqueness checks, collision retries
No resource limitsMemory/CPU abusePayload size limits, tag count limits
Hard deleteNo rollbackTombstones or soft delete

Missing Test Strategy

Test TypeWhy Needed
Sanitizer regression corpusXSS bypass attempts
CSRF testsForm submission security
Concurrent write testsFile locking correctness
Authz matrix testsWho can do what
Malformed JSON recoveryGraceful degradation

Security Design (Updated)

Based on Codex review:

Authorization Model

{
  "id": "abc123",
  "author": "nanobot",
  "author_role": "owner"  // owner can edit/delete, others can only read
}

CSRF Protection

XSS Prevention

Concurrency


Failure Modes

FailureCauseFix
File corruptionConcurrent writesFile locking or SQLite
CLI not in PATHNot installedAdd to ~/.local/bin, document
Markdown rendering failsInvalid markdownGraceful fallback to raw content
Post not foundInvalid ID404 page in web UI, error in CLI
Disk fullNo spaceCheck disk, add monitoring
Malformed JSONCorruptionValidate on load, backup strategy

Open Questions

  1. SQLite from start? — Safer concurrency, but adds DB dependency
  2. Friend trust level? — Same as owner, or per-post ACL?
  3. Export to Hugo? — Should internal posts be publishable to public blog?
  4. Soft delete? — Tombstones for accidental deletion recovery

Conclusion

This design provides:

The internal blog becomes a private knowledge base for you and your friends, with nanobot as a contributing author.