docs: real README and update Claude auth section in CLAUDE.md

- Replaces the create-next-app boilerplate README with a real one:
  what the project does, the 8-agent pipeline table, tech stack, local
  dev, configuration via the Settings UI, multi-tenant App model,
  Unraid deployment, and repo layout.
- CLAUDE.md "Claude Auth in Docker" no longer claims .env is the only
  way to set the OAuth token — describes the Settings page as primary,
  .env as bootstrap fallback, mentions the Test button, and notes that
  Anthropic exposes no UI to list/revoke setup-tokens.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Trey T
2026-05-03 21:13:45 -05:00
parent 55fb221faa
commit 8afbf68f4c
2 changed files with 171 additions and 25 deletions
+7 -4
View File
@@ -72,11 +72,14 @@ ssh unraid "cd /mnt/user/appdata/marketing && docker compose down && docker comp
``` ```
### Claude Auth in Docker ### Claude Auth in Docker
Claude Max uses OAuth, tokens stored in macOS Keychain. For headless Docker: Claude Max uses OAuth tokens stored in macOS Keychain locally, but the headless Docker container has no keychain, so it needs the OAuth access token explicitly. The token is rotated from the **Settings page** (`/settings` → Claude card); the DB value is injected into the spawned `claude` subprocess env at launch time and overrides `CLAUDE_CODE_OAUTH_TOKEN` from the container env. The Test button on the same card validates the token by hitting the Anthropic messages API and surfaces 401s as "Token expired or invalid".
To mint a token:
1. Run `claude setup-token` locally, open the magic link in browser 1. Run `claude setup-token` locally, open the magic link in browser
2. Extract the access token: `security find-generic-password -s "Claude Code-credentials" -a "$(whoami)" -w` 2. Extract the access token: `security find-generic-password -s "Claude Code-credentials" -a "$(whoami)" -w | python3 -c 'import sys,json; print(json.load(sys.stdin)["claudeAiOauth"]["accessToken"])'`
3. The JSON has `claudeAiOauth.accessToken` — use just that value 3. Paste it into Settings → Claude → Save (no rebuild required)
4. Set `CLAUDE_CODE_OAUTH_TOKEN=<access-token>` in the Unraid `.env`
`CLAUDE_CODE_OAUTH_TOKEN` in `.env` still works as a bootstrap fallback (used on first boot before any DB value is saved, or if the DB is wiped). There is no Anthropic UI to list or revoke `setup-token` outputs — they live ~1 year. Treat each one like a password.
### Volume Permissions ### Volume Permissions
Host directories must be owned by UID 1000 (node user in container): Host directories must be owned by UID 1000 (node user in container):
+164 -21
View File
@@ -1,36 +1,179 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). # Marketing Command Center
## Getting Started A Next.js dashboard that turns the Claude Code CLI into a marketing team.
Spawns `claude` as a subprocess to run an 8-agent pipeline that researches
trends, writes ad scripts, generates static and video creatives, drafts
platform-tuned copy, and prepares a publish manifest — all per campaign,
per app, per platform.
First, run the development server: Used internally to drive social campaigns for the 88Oak app portfolio
(honeyDue, Reflect, etc.). Deployed on an Unraid server at
`marketing.88oakapps.com`.
---
## What it does
You create a Campaign in the UI. The web app spawns
`claude -p <prompt> --output-format stream-json` once per agent, in order:
| # | Agent | Output |
|---|---|---|
| 1 | **Trend Scout** | `trend_report.json` — viral hooks, competitor angles, formats (Tavily searches) |
| 2 | **Marketing Research** | `research_results.json` + `research_brief.md` (deep Tavily) |
| 3 | **Script Writer** | Hook/body/CTA scripts per platform, timed for video |
| 4 | **Gemini Ad Designer** | Photo-real static ads via NanoBanana MCP (Google Gemini) |
| 5 | **Poster Ad Designer** | "Museum-quality" HTML→PNG posters via Playwright |
| 6 | **Video Ad Producer** | Remotion compositions rendered to MP4 (Reels, TikTok) |
| 7 | **Copywriter** | Platform-tuned captions with hashtags |
| 8 | **Distribution** | `Publish_manifest.md` — never auto-publishes |
Each agent reads its `pipeline/skills/<name>/SKILL.md` and the campaign's
brand/product knowledge files before producing output. Progress streams
back to the UI over SSE; completed assets are scanned into the DB and
shown in the campaign's asset gallery.
From there: thumbs-up/down to teach style preferences (fed back into
future Gemini prompts as `reference_images`), spawn variations of a
winner, repurpose to other dimensions, or push individual assets to
[Postiz](https://postiz.com) for scheduling.
For the agent details and folder conventions, see
[`pipeline/CLAUDE.md`](./pipeline/CLAUDE.md).
---
## Tech stack
- Next.js 16 (App Router) + React 19 + TypeScript 5
- Tailwind 4 + shadcn/ui
- Prisma 7 over SQLite (`better-sqlite3` adapter)
- NextAuth 5 (credentials provider, `trustHost: true` for the reverse proxy)
- Playwright (HTML→PNG)
- Remotion (video rendering, project at `pipeline/remotion-ad/`)
- Claude Code CLI spawned via `child_process.spawn` (NOT the Anthropic SDK)
- NanoBanana MCP for Gemini image generation
- Tavily for web research
---
## Local development
```bash ```bash
npm run dev npm install
# or npx prisma db push
yarn dev npx prisma db seed # creates admin user + honeyDue app
# or npm run dev # http://localhost:3000
pnpm dev
# or
bun dev
``` ```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. Default login: `admin@localhost` / `admin123` (override with `ADMIN_EMAIL`
/ `ADMIN_PASSWORD` env vars). The Claude Max OAuth flow on your dev
machine handles auth automatically — no token needed locally as long as
you've signed into the `claude` CLI once.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. ---
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. ## Configuration
## Learn More Every third-party credential is configured at **Settings** (`/settings`)
and stored in the `Setting` DB table. DB values override `.env` at
runtime. Each integration card has a **Test** button that hits the real
API to verify the credential.
To learn more about Next.js, take a look at the following resources: | Integration | What it's for |
|---|---|
| **Claude** | OAuth access token for the `claude` CLI subprocess. Token expires (~1 year) — refresh here when launches start failing with auth errors. |
| **Tavily** | Web research for the Trend Scout and Research agents. |
| **Gemini** | Google Gemini powers NanoBanana MCP for static ad generation. |
| **Postiz** | Self-hosted social scheduling (Instagram, TikTok). |
| **Nextdoor** | Direct Nextdoor Ads API integration. |
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. To mint a Claude Code OAuth token (for headless / Docker use):
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! ```bash
claude setup-token
# extract the access token from your keychain:
security find-generic-password -s "Claude Code-credentials" -a "$(whoami)" -w \
| python3 -c 'import sys,json; print(json.load(sys.stdin)["claudeAiOauth"]["accessToken"])'
```
## Deploy on Vercel Paste the result into Settings → Claude → Save. There is no Anthropic UI
to list or revoke `setup-token` outputs — treat each one like a password.
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. ---
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. ## Apps (multi-tenant)
The same pipeline serves multiple products. Each `App` row in the DB
carries its own brand colors, brand identity markdown, product info,
platform guidelines, and learned style preferences. At launch time,
`launchPipeline` writes the active app's knowledge into
`pipeline/_knowledge/` and copies the app's `icon.png` / `phone.png`
into Remotion's `public/` directory. Switch active apps from the
sidebar.
Per-app assets live at `pipeline/apps/<slug>/`.
---
## Deployment (Unraid)
The app runs in a single Docker container behind Nginx Proxy Manager at
`marketing.88oakapps.com`. Source lives at
`/mnt/user/appdata/marketing/` (disposable, rsynced from dev).
Persistent data is bind-mounted from `/mnt/user/downloads/marketing/`
(`db/`, `outputs/`, `knowledge/`).
```bash
# Sync source (preserves Unraid-specific .env and docker-compose.yml)
rsync -avz \
--exclude='node_modules' --exclude='.next' --exclude='prisma/data' \
--exclude='pipeline/outputs' --exclude='pipeline/remotion-ad/.next' \
--exclude='pipeline/remotion-ad/node_modules' \
--exclude='.env' --exclude='.env.local' --exclude='docker-compose.yml' \
--delete \
./ unraid:/mnt/user/appdata/marketing/
# Rebuild + restart
ssh unraid "cd /mnt/user/appdata/marketing && docker compose down \
&& docker compose build app && docker compose up -d"
```
Full deployment notes (`docker-compose.yml` shape, volume permissions,
Dockerfile quirks) are in [`CLAUDE.md`](./CLAUDE.md).
---
## Repo layout
```
app/ Next.js App Router
(auth)/ Login
(dashboard)/ UI: campaigns, assets, apps, settings, trends
api/ REST endpoints (campaigns, assets, settings, files)
components/ React components incl. shadcn/ui
lib/
claude.ts Subprocess orchestration, prompt building
scanner.ts Walks pipeline outputs into Asset rows
settings.ts DB-backed config + per-integration health checks
postiz.ts Postiz publishing
variations.ts "More like this" via Gemini
repurpose.ts Reformat to other aspect ratios
nextdoor.ts Direct Nextdoor Ads API
prisma/
schema.prisma User, App, Campaign, AgentRun, Asset, ...
seed.ts Admin user + default app
pipeline/
CLAUDE.md Agent pipeline architecture (read this)
skills/<agent>/SKILL.md Per-agent instructions the spawned Claude reads
apps/<slug>/ Per-app assets (icon, phone frame, screenshots)
knowledge/ Default knowledge (overridden per-app at runtime)
outputs/<task>_<date>/ Generated campaign deliverables
remotion-ad/ Remotion video project
```
---
## License
Private / internal.