RC-1: Gitea org fallback already removed (no-op, confirmed)
RC-3: Push/pull now explicitly target origin main (HEAD:main) in both
pod_git_operations.go and claudebox/git.go — fixes Woodpecker webhook
trigger by ensuring pushes always land on the main branch
RC-4: wait_for_pipeline records baseline pipeline number before polling;
only returns success when a NEWER pipeline completes — prevents false
positive when a prior pipeline was already success
RC-5: Redis WRONGPASS fixed on live persona-community-5 instance; platform
gap noted (no reprovision endpoint for Redis ACL drift)
RC-6: Removed on_error:continue from all infra provisioning steps (add-db,
add-redis) across persona-community, slackpath-2/3/4/5 trees — infra
failures now fail the tree instead of silently continuing to a crash
RC-7: Added .pnpm-store/ to skeleton .gitignore — prevents thousands of
cache files being committed by agents after pnpm install
RC-2: Updated all 12 cookbook trees — git_clone_url jordan/ → threesix/
(24 occurrences across all slackpath, aeries, full-stack, genkit trees)
Also: strings.Cut and strings.SplitSeq lint fixes in pod_git_operations.go
and claudebox/git.go
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
NOTIFY_URL is a global platform credential; NOTIFY_API_KEY is project-
scoped and may not be provisioned if notify setup failed or the
notifyProvisioner wasn't configured. Previously the service would crash
on startup with "invalid configuration: API key is required" when
NOTIFY_URL was set but NOTIFY_API_KEY was missing.
Now the condition checks both: only initialize the notify client when
both NOTIFY_URL and NOTIFY_API_KEY are set. When either is absent, fall
back to log-only mode with a warning (instead of os.Exit(1)).
This is the correct behavior: email not delivered is survivable, but a
service crash on startup breaks the entire application.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without MustInit(), viper.AutomaticEnv() is never called, so Viper
cannot read environment variables injected by K8s secrets (envFrom).
This caused DATABASE_URL to always appear empty in deployed services,
forcing them into standalone/in-memory mode even when a database was
provisioned.
os.Getenv() calls like JWT_SECRET worked fine (direct syscall).
Viper-backed reads like DATABASE_URL did not (require AutomaticEnv).
Added pkgconfig.MustInit() call at the top of main() in both the
service component template and the full-monorepo example-api.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The usePersonaGeneration hook was created on disk but never committed
to git, so rendered projects had a broken import in index.ts causing
TypeScript build failures in CI.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add ErrAnchorRequired sentinel to pkg/album — replaces fragile string equality check
used for 422 detection; callers now use errors.Is()
- Extract parseShotIndex() helper in album handler — replaces fmt.Sscanf which silently
accepted partial parses like "12abc"; strconv.Atoi requires the full string to be numeric
- Restructure caption saves in album/handler — captions now written outside the
len(img.Data) > 0 gate, so URL-only providers (no bytes returned) still get captions
- Add storage.FetchURL() shared utility — removes fetchBytes/downloadURL duplication
across album and generation packages; callers control timeout via their http.Client
- Add video captions to VideoHandler — same caption sidecar pattern applied to videos
- Add persona generation event types to realtime package — persona_spec_*, persona_image_*,
persona_video_* events added to EventType union and usePersonaGeneration hook exported
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After each successful image upload to storage, a sidecar `.caption`
file is uploaded at the same path with `.caption` extension containing
the exact prompt used to generate the image.
Coverage:
- generation/handlers.go: ImageHandler → media/{userID}/images/{jobID}_{i}.caption
- album/handler.go: AnchorHandler → albums/{userID}/{albumID}/anchor.caption
- album/handler.go: ShotHandler → albums/{userID}/{albumID}/shots/{shotIndex}.caption
- personagen/service.go: generatePosition → personas/{specID}/images/{pos:02d}.caption
Caption failures are logged at warn level and never abort the job.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- specgen: extend dnaLLMResponse with heritage fields; conditionally extend
Stage 4 prompt for EthnicityMixed to ask LLM for primary_heritage,
secondary_heritage, and mix_percentage; populate IdentityDNA fields from
response so mixed personas get a real heritage breakdown
- imagegen: buildIdentitySection() produces "East Asian and Latina/Hispanic
heritage" description for mixed personas instead of generic "mixed-race"
- videogen: add genderPronouns() helper; replace hardcoded she/her with
pronoun set across all 4 video prompts; generateVideo() returns raw bytes
so caller can upload to storage
- service: GenerateVideo() uploads video to storage and sets VideoSpec.URL;
anchor ordering ensures position 1 is generated first; emit
persona_video_failed SSE event on non-fatal video failures; replace manual
fold helpers with strings.ToLower + strings.Contains
- worker/main: register persona_generate handler when both AI managers ready
- docs: add persona_video_failed to SSE events reference in personagen.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously SendOTP silently dropped requests for unknown emails, so new
users had no passwordless path in. Now:
- SendOTP: if REGISTRATION_ENABLED and email unknown, generates and
sends the code anyway (UserID nil until verify)
- VerifyOTP: if email unknown after valid code, auto-registers the user
(emailVerified=true — OTP delivery proves ownership, name defaults to
email local-part) then creates a session
REGISTRATION_ENABLED=false continues to block unknown emails at SendOTP,
preserving invite-only / closed-beta behaviour.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
In-memory auth codes are ephemeral — they're wiped on server restart.
Previously, codes were only visible via email delivery. If the server
restarted between OTP send and OTP verify, the code would be lost.
Now memory.AuthCodeRepository.Create() always logs the code to stdout
with a [DEV] prefix. This gives developers a reliable fallback regardless
of whether NOTIFY_URL is set. Updated CLAUDE.md to document this behavior
and the DEV_USER_EMAIL env var.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
In standalone mode (no DATABASE_URL), the in-memory user store only had
hardcoded demo accounts. Any real email the developer used was lost on every
server restart, causing OTP requests to silently fail with "unknown email".
NewUserRepository now accepts devEmail + devPassword. If DEV_USER_EMAIL is
set, that account is seeded on every startup alongside the demo users. The
developer's email is always registered, OTPs route to notify (or log to
console), and re-renders/restarts no longer break the auth flow.
New config fields: DevUserEmail (DEV_USER_EMAIL) / DevUserPassword
(DEV_USER_PASSWORD, default: "DevPassword1").
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Every project generated from the skeleton now ships with styled,
production-ready transactional emails out of the box.
New pkg/email package:
- Renderer: loads templates from caller-provided embed.FS, inlines CSS via
douceur at startup, derives plain text via goquery for multipart delivery
- DevHandler: live browser preview at GET /dev/emails and /dev/emails/{purpose}
(development only, never mounted in production)
- CSSInlineErr field on RenderedEmail so callers can log degraded renders
New service component templates:
- internal/email/embed.go.tmpl — embeds template FS (uses all: prefix for _*.html)
- internal/email/renderer_test.go.tmpl — 9 tests covering all purposes + brand injection
- internal/email/templates/ — 5 HTML email types (login_otp, email_verify,
magic_link, password_reset, welcome) + 5 shared partials (_layout, _header,
_footer, _button, _code_box)
Updated service component templates:
- config.go.tmpl — brand fields: AppName, AppURL, SupportEmail, LogoURL, BrandColor
- main.go.tmpl — wires renderer at startup, logs template count
- routes.go.tmpl — mounts /dev/emails in development; EmailRenderer in Dependencies
- notify.go.tmpl — renders HTML before sending; warns on CSS inlining failure
- go.mod.tmpl — adds douceur, goquery, gorilla/css, andybalholm/cascadia
Deleted: internal/adapter/email/helpers.go.tmpl (replaced by meta.yaml + renderer)
Fix: template directory named email_verify (matching domain.PurposeEmailVerify)
rather than verify_email — the mismatch caused all verification emails to fail
with "unknown email purpose" at send time while tests passed (tests called
Render directly with the wrong name).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix no-op RequireProjectAccess middleware to enforce project_ids
- Apply project access middleware to all project-scoped routes
- Filter GET /projects by allowed project IDs for restricted keys
- Add GET /me endpoint with key identity, scopes, and project access info
- Add PATCH /keys/{id} for partial key updates (name, scopes, project_ids, allowed_ips, expires_in)
- Add GET/POST/DELETE /projects/{id}/access for project-centric access management
- Auto-grant creating key access when using POST /project/create-and-build
- Accept grant_to_key_ids in create-and-build to grant multiple keys on project creation
- Move newProvisionerWithDeps test helper from production code to test file
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
These components use useState/useRef hooks but lacked the Next.js 'use client'
directive, causing the Next.js app build to fail with Server Component errors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two distinct fixes:
1. Database terminology: Make it crystal clear that generated projects use
CockroachDB in production and PostgreSQL for local dev, while the rdev
platform itself uses PostgreSQL. Updated 15 files across skeleton agents,
component templates, cookbook trees, and platform docs.
2. Video storage: VideoHandler was ignoring vid.Data bytes (already downloaded
by the Gemini adapter with auth) and re-downloading from the provider URL
with a plain GET — which fails because Gemini URLs require API key auth.
Now uses vid.Data first, falls back to downloadURL only for public URLs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds complete media storage pipeline with GCS presigned uploads, AI image/video/text generation
via queue-based workers, realtime SSE event streaming, and comprehensive skeleton packages
(storage, mediagen, textgen, generation, realtime, persona, routing, ai-client). Includes
security fixes for media delete authorization, nil pointer guards in handlers, video persistence
via download-then-upload, consistent signed URLs, and Image→ImageIcon rename to avoid DOM collision.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The architect API returned "failed to start conversation" because
projectRepo.Get() failed — the in-memory K8s repo watches the rdev
namespace but projects deploy to the projects namespace. Made project
lookup non-fatal with fallback to default pod. Added error logging to
all architect handler methods (were silently swallowing errors).
Also adds setup-hooks, commit-after-qa, and pre-merge-validate steps
to the foundary cookbook tree for git hooks and code quality gates.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Components are scaffolded before CI builds their images. Previously deployments
started with 1 replica, causing ImagePullBackOff until the first build completed.
Now deployments start at 0 replicas; CI deploy steps scale to 1 after verifying
the image exists in the registry.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add --connect-timeout 10 and --max-time 15 to all verify step curl
calls to prevent hanging on registry health checks
- Fix cli template: depends_on [deps] -> [preflight] for consistency
- Add cross-reference comment to service template about verify logic
being replicated across all 5 component templates
- Document component CI step rules in composable-monorepo.md
- Compile regexes at package level instead of per-call in
component_updates.go
- Add component_updates_test.go
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add UndeployAll() using label selectors to clean up monorepo components
on project deletion (replaces name-based Undeploy in DeleteProject and
the direct undeploy handler)
- Add ResourceGC background worker that periodically finds K8s resources
whose project label has no matching DB record, deletes after 1h safety
window
- Widen deployer client type from *kubernetes.Clientset to
kubernetes.Interface for testability
- UndeployAll accumulates errors via errors.Join instead of failing fast
- Add checkout/checkin sidecar dev flow: temporary git tokens, branch
checkout, review on checkin with cleanup workers
- Add interactive sessions: pod binding, command execution, SSE streaming,
ephemeral preview URLs with session cleanup workers
- Add GET /workers/pool endpoint for aggregate capacity and queue depth
- Add sessions:read and sessions:execute auth scopes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Agents were generating `:id` (Echo/Gin style) instead of `{id}` (chi style),
causing routes to not match. Updated api-designer, go-specialist agents and
skeleton CLAUDE.md with explicit CRITICAL notes about brace syntax.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When req.Template is empty, it defaults to 'skeleton' but the check
in createInitialDeployment only matched 'skeleton' explicitly, not
empty string. This caused a broken deployment to be created for
monorepo projects with a non-existent image.
Root cause: slackpath-5 creates project with empty template, which
defaults to skeleton, but createInitialDeployment was still creating
a root deployment that references registry.threesix.ai/{project}:latest
which never gets built (skeleton has no root Dockerfile).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When docs infrastructure doesn't exist, the docs build steps should
gracefully skip without failing the entire pipeline.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The raw gcr.io/kaniko-project/executor with commands: doesn't work
properly in Woodpecker. Switch to woodpeckerci/plugin-kaniko with
settings: to match other component builds.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The registry.threesix.ai uses a self-signed certificate.
Service builds use plugin-kaniko with skip-tls-verify, but docs
build used raw kaniko executor without TLS bypass, causing exit 128.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When --context=docs is set, the --dockerfile path should be relative
to the context directory. Changed from docs/Dockerfile.nginx to
Dockerfile.nginx since kaniko already looks in the docs/ directory.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
middleman-syntax ~> 3.2 requires rouge ~> 3.2, but Gemfile had rouge ~> 4.0
causing bundle install to fail with version resolution error.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds complete Slate documentation infrastructure to generated projects:
- docs/ directory with Gemfile, config.rb, and source templates
- Dockerfile for building docs site
- Dockerfile.nginx for serving static docs
- generate-docs.sh script for CI integration
- Claude command for AI-assisted docs generation
- OpenAPI → Slate markdown conversion via widdershins
Also includes:
- --export-openapi flag for service binaries
- DNS provisioning for docs.{domain} subdomain
- Updated project_infra for docs DNS records
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The export-openapi step was running in parallel with component builds
because it had no explicit dependency. This could cause docs generation
to run before component services were fully built.
Changes:
- Add build-complete step with NO depends_on (waits for ALL prior steps)
- Make export-openapi depend on build-complete
- Complete docs pipeline: export-openapi → generate-docs → build-docs →
build-docs-image → deploy-docs
- Update verify step label selector to use project= instead of app=
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Empty go.sum files were causing Docker builds to fail because
Go couldn't verify dependencies. Added go mod download steps
for both pkg and component directories before building.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Updates slackpath-2 and slackpath-4 to use POST /projects/{id}/components/batch
for adding multiple Go components atomically in a single git commit. This
prevents the go.work race condition where individual commits reference modules
that don't exist yet.
Also adds on_error: continue for infrastructure provisioning steps that may
already exist from skeleton (redis, postgres).
Verified:
- slackpath-1: ✅ Complete (wait_build polled 5 times, detected success)
- slackpath-2: ✅ Complete (wait_build polled 111 times, detected success)
- slackpath-3: ✅ Infrastructure passed (worker capacity limited testing)
- slackpath-4: ✅ Infrastructure passed (worker capacity limited testing)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Three coordinated fixes for CI pipeline race conditions:
1. Woodpecker step dependencies: Added depends_on: [deps] to all 6 component
templates (service, worker, cli, app-astro, app-react, app-nextjs) so build
steps wait for go work sync to complete.
2. Idempotent resource provisioning: Modified provisionResources() to check
for existing database/cache before creating, preventing "already exists"
errors on component re-adds.
3. Batch component endpoint: POST /projects/{id}/components/batch enables
atomic multi-component additions in a single git commit. Validates all
components upfront, provisions infra sequentially, commits code components
atomically.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Worker template fixes:
- Replace panic() with logger.Error() + os.Exit(1) for config errors
- Remove double-timeout application (context + middleware)
- Add error message truncation to prevent log bloat
- Use named constants for shutdown grace period and stale check interval
Skeleton pkg/auth fixes:
- Fix error wrapping to use %w consistently in jwt.go
- Add GetUserOrError() as safe alternative to MustGetUser() panic
Skeleton pkg/queue fixes:
- Check RowsAffected() errors instead of ignoring them
- Add input validation to EnqueueWithOptions (require job type, cap retries)
- Add log truncation for error messages
- Fix inaccurate doc comment claiming exponential backoff
Worker timeout consolidation:
- Add internal/worker/timeouts.go with named constants
- Migrate all workers to use timeout constants
Cleanup:
- Remove obsolete slack-preparation-thoughts.md files
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Major changes:
- Add internal/logging package with field constants, context propagation,
sensitive data auto-redaction, and per-component log levels
- Add worker timeout constants (TimeoutQuickOp, TimeoutHealthCheck, etc.)
- Extend SDLC with callback handlers, generate endpoints, and executor
- Add new cookbook trees for aeries and slackpath progression
- Add skeleton templates for queue, realtime, and microservices
- Add worker component template with async job processing
- Refactor services and handlers to use new logging infrastructure
- Split component.go into component_infra.go and component_listing.go
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds AddIngressPath and RemoveIngressPath to the Deployer interface
for managing per-component ingress rules in monorepo projects.
- Implement conflict retry logic for concurrent ingress updates
- Add K8s client interface for testability
- Add comprehensive unit tests for ingress path operations
- Add component deployment and teardown methods to ComponentService
- Update service templates with OpenAPI spec improvements
- Add evolving-app cookbook tree for reference
- Split resources.go into resources_ingress.go for path-based routing
- Split component.go into component_deploy.go for deployment helpers
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use glob pattern go.work.su[m] instead of go.work.sum to allow
the COPY to succeed even when go.work.sum doesn't exist yet.
This happens on fresh monorepos before dependencies are synced.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Composable monorepo CI fixes:
- Add empty go.sum.tmpl files for pkg, service, worker, and cli components
- Fix Dockerfile.tmpl glob patterns (COPY go.work.sum* is invalid in Kaniko)
- Add deps step to CI that runs go work sync and go mod tidy before builds
- Fix scalar-go dependency version (v0.1.2 doesn't exist, use v0.13.0)
Health endpoint improvements:
- Add registry health check (zot OCI /v2/ endpoint)
- Add health metrics for CI, registry, and Git
- Add /health/ci endpoint for Woodpecker health
Visual verification scaffolding:
- Add Playwright pod and scripts ConfigMap
- Add vision.md and implementation breakdown plan
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add pass/fail/needs-fix CLI commands to cmd/sdlc/cmd_artifact.go
- Add 3 new methods to SDLCExecutor interface in internal/port
- Implement methods in kubernetes adapter
- Add service methods to SDLCService
- Add HTTP handlers for POST .../artifacts/{type}/pass|fail|needs-fix
- Update 6 skeleton commands to evaluate and set artifact status
- Update test mocks
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add branch lifecycle commands (branch, merge, archive) to the SDLC CLI.
Introduce orchestrator handler and service for multi-step SDLC workflows.
Expand skeleton template with 15 Claude commands covering the full feature
lifecycle. Extend classifier rules, error types, and executor port for
branch operations. Split rules.go and classifier_test.go to stay within
500-line limit.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add best-of-best Claude Code configuration from local setup to the
composable monorepo skeleton template, giving new projects a powerful
starting configuration.
Commands added (4):
- do-parallel: Execute tasks in parallel waves with agent selection
- remember: Store learnings as institutional memory
- prepare: Pre-implementation readiness assessment
- root-cause: Root cause analysis with parallel investigation
Skills added (5):
- orchestrated-execution: Task pipelines with implementation → review → fix
- root-cause-analyst: Systematic diagnosis with confidence scoring
- knowledge-librarian: Organize learnings in ai-lookup/ structure
- feature-verifier: Verify features work with evidence matrix
- prepare: Binary outcome readiness assessment (brief or gap list)
Agents added (1):
- quality-engineer: Code quality, test coverage, error handling reviewer
All Citadel-specific references genericized to use skeleton's existing
agents (go-specialist, testing-strategist, security-architect, etc).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>