Skip to content
← All work

P—12 Case study · Tools & automation

Portfolio automation

Role

Designer and builder

Status

active

Started

—

Last activity

Sep 2026

Stack

6 technologies

Overview

Publishing a portfolio update usually means editing content files, opening a pull request and waiting on a deploy. Miss a validation rule and the site breaks. This system removes that loop: run /portfolio inside OpenCode against any local folder or GitHub repo, approve a preview, and the live site shows a dated update a few minutes later.

The model drafts the prose as a batch of operations such as project.create, project.patch and update.add. A five-tool plugin reads git history and the project's portfolio record, validates the payload against one shared schema, and dispatches a GitHub Actions workflow. The workflow validates again, applies the batch all-or-nothing, and commits content as one JSON file per project and one per update so concurrent writes never conflict. Field ownership hashes protect anything a person edited by hand.

Cloudflare Pages rebuilds on every push, with content validation as the prebuild step so a bad record fails the build and the previous deploy stays live. A weekly workflow refreshes renamed repos, hides code links for repos that went private, and keeps one tracking issue for stale projects. No server, no background process, no paid service.

Impact

  1. 01Built a five-tool OpenCode plugin that publishes portfolio updates from a chat command
  2. 02Centralized every validation rule in one schema executed at preview, workflow and prebuild
  3. 03Added field ownership hashes so hand edits on GitHub are never overwritten by automation
  4. 04Shipped idempotent retries, push-race recovery and revert support in the apply workflow

Features

01

Chat to live site

Run /portfolio in OpenCode, approve a preview, and the site updates in minutes.

02

Shared schema validation

One schema.mjs runs at preview, in the workflow and as prebuild, so nothing unvalidated reaches the site.

03

Field ownership

Hashes on every bot-written field skip hand edits unless the user explicitly overrides.

04

Conflict-free content

One JSON file per project and one per update, so concurrent publishes never collide.

05

Preview approvals

Nothing reaches the site until the user approves a field-by-field preview in chat.

06

Reliable deploys

Idempotent request IDs, push-race retries, and revert support keep main consistent.

07

Weekly sync

A scheduled workflow fixes renamed repos, hides dead code links and tracks stale projects.

Architecture

01OpenCode chat02portfolio skill03portfolio plugin04portfolio_context05Agent drafts ops06portfolio_preview07portfolio_publish08GitHub Actions apply09content JSON in repo10Cloudflare Pages build11Live site

The flow starts in OpenCode: the portfolio skill tells the agent the workflow and writing rules, and the /portfolio command loads it. The portfolio-publisher plugin exposes five tools over one shared core. portfolio_context reads git in the target folder, fetches the project's record and recent updates from the portfolio repo through the GitHub API, and returns a fact sheet. The agent drafts ops from that sheet and the files it reads. portfolio_preview injects repo facts, canonicalizes tech names, validates with schema.mjs, scans for secrets, and stores the payload under a 12-character hash. On approval portfolio_publish gzips the payload and dispatches portfolio-apply.yml. The workflow decodes it, runs apply.mjs, runs build.mjs --check, commits to main, and pushes. Cloudflare Pages builds the commit with build.mjs as prebuild, regenerates the site data, and serves the deploy. utils/data/portfolio-content.js is the only module the site components import, feeding the projects list, the currently-working-on carousel and the per-project dev log.

Stack

TypeScriptJavaScriptShellNode.jsNext.jsReact

Development log

  1. · Started

    Portfolio automation shipped end to end

    The skill, five-tool plugin, shared schema and GitHub workflows are installed and working. A smoke dispatch applied and idempotently replayed, the macOS path fix took end-to-end tests to green, and the site now groups projects by category with a generated currently-working-on carousel.