AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
Nuxt 4 레이어로 웹사이트를 감싸 기록 도구를 제공, 모든 방문·캡처·오류를 실시간 스트리밍
A Nuxt 4 layer that wraps your website in a recording instrument — every visit, capture, and error, human or machine, streamed raw to where you decide to double down or kill.
개발 도구TypeScript · VueGitHub @incubrain온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기IncuBrain Foundry is a Nuxt 4 template optimised for creating AI-native businesses
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗A Nuxt 4 layer for standing up a marketing site that streams the full signal of whether it is working.
Foundry is the wireframe. You write content, deploy, and wire nothing — the site captures what visitors do (visits, and intent through the convert components) and what the site itself reports (errors, warnings), buffers it server-side in one envelope, and hands it to an external consumer over an authenticated cursor endpoint. We pull it into Polaris; you can point a Grafana-class puller at the same endpoint. Foundry ends at the stream — no charts, no dashboards, no anomaly detection inside the site.
The second pillar is agent-readiness. Agentic traffic is expected to dwarf human
traffic, so Foundry sites ship MCP tools, llms.txt, raw-markdown redirects, and a strong
SEO/OG stack — and every signal row is classified human | agent | bot server-side, because
that split is itself signal.
Stack: Nuxt 4 · Nuxt Content · Nuxt UI · Tailwind v4 · TypeScript
npm install @incubrain/foundry
// nuxt.config.ts
export default defineNuxtConfig({
extends: ['@incubrain/foundry'],
})
# .env — this is the entire required surface
NUXT_SIGNAL_EXPORT_TOKEN=<random-secret> # bearer token for the export endpoint
NUXT_PUBLIC_SITE_ID=my-site # optional — defaults to the request host
Write content under content/, deploy, point your consumer at
/api/_signals/export. See examples/foundry for a complete app.
Everything the site captures — analytics events and error/warning logs — becomes one
SignalRow in a capped server-side ring buffer. Nothing is pushed anywhere. An external
consumer pulls with a cursor.
client events → signal provider ─┐
client errors → errors.client ───┼→ POST /api/_signals/ingest ─┐
│ ├→ ring buffer (unstorage)
form captures → /api/v1/webhook ─┘ │ ↓
server errors → signal-errors plugin ──────────────────────────┘ GET /api/_signals/export
?since=<seq>&limit=<n≤2000>
→ { rows, cursor, site }
The envelope — one shape for both kinds:
SignalRow {
id, seq, ts, site,
kind: 'event' | 'log',
name,
severity?, // logs
visitor?, // { hash, class: 'human' | 'agent' | 'bot', device, browser, os, ... } — server-side
page?, referrer?, utm?,
review?, // ?polaris_review=<token> — this page load only, never persisted
data?
}
useEvents() → the signal provider → a debounced batch
queue, flushed with sendBeacon on pagehide.visitor.hash, a
server-side sha256(daily_salt + site + ip + user_agent). The salt rotates at UTC
midnight and the old one is deleted, so a visitor is one value for a day and unlinkable
across days. Nothing is written to the visitor's device and the raw IP is never stored,
so no consent banner is needed for signal capture.ui.click ({ target, label?, section? }), ui.section ({ section, visible }), and ui.page ({ from? }). They are
content-free by construction — authored element identity and labels only, never pixel
coordinates, input values, or keystrokes. Sections are named by data-section or a plain
<section id>; SectionWrapper stamps it for you. data-signal-ignore excludes a subtree.window.onerror, unhandledrejection, Vue errorHandler) land in the
same stream as kind: 'log' rows. So do Nitro request errors, server-side./api/v1/webhook (historical route name — it is the
form-capture endpoint, not a webhook sender), pass honeypot/timing and zod validation, and
land as a form_submitted row. The server is the durable capture point.User-Agent on every ingest path. A
client-supplied value is always overwritten, never trusted.seq is monotonic; consumers send back the last cursor they saw.Pulling the stream:
curl -H "Authorization: Bearer $NUXT_SIGNAL_EXPORT_TOKEN" \
"https://your-site.com/api/_signals/export?since=0&limit=500"
# → { rows: [...], cursor: 512, site: "my-site" }
The endpoint fails closed: with NUXT_SIGNAL_EXPORT_TOKEN unset it returns 503, never open
data. Rows live in useStorage('signals') — memory by default, 100 000 rows, oldest
evicted. Mount nitro.storage.signals to an fs/KV driver if they must survive a restart.
| Surface | What ships |
|---|---|
/api/_health | Unauthenticated liveness+identity check for external monitors (Polaris): { ok, service: 'foundry', version, siteId, timestamp }, Cache-Control: no-store. Pure computation — no storage or content access. |
| MCP tools | list-pages, get-page, what-changed — auto-registered from server/mcp/tools/, served by @nuxtjs/mcp-toolkit. Visit /_mcp/tools in dev to verify. |
llms.txt | /llms.txt + /llms-full.txt ship by default via nuxt-llms (a real layer dependency, zero config); sections auto-populate from your content collections. Override with an llms: config in your app — see examples/foundry/nuxt.config.ts. |
| Raw markdown | The markdown-rewrite module writes Vercel edge redirects so Accept: text/markdown or a curl/* UA on a page URL serves /raw/<path>.md, and / serves llms.txt. No-op off Vercel and in dev. |
| SEO / OG | @nuxtjs/seo (sitemap, robots, schema.org, link checker, canonical redirects) plus a Satori OG image component for landing pages. |
| RSS | Config-driven feeds from any content collection — rss: { feeds: {} } in your app config, served at /rss/{key}. |
Content is YAML and markdown, edited by whoever owns the site — not code. The layer exports
zod schemas you compose in your own content.config.ts:
import { basePageSchema, baseFaqSchema, baseConfigSchema, baseNavigationSchema }
from '@incubrain/foundry/schemas'
content/
├── pages/ Markdown pages (basePageSchema)
├── faq/ FAQ entries (baseFaqSchema)
└── config/
├── site.yml Site config (baseConfigSchema)
└── navigation.yml
baseTeamSchema and bannerSchema are exported too.
Sections are deliberately minimal. The layer ships SectionWrapper — an accessible
UPageSection wrapper that emits a section_view_<id> event on intersection and sets
data-testid. Concrete sections (Hero, Offer, …) live in your app, not the layer: an
opinionated design system is out of scope on principle.
Convert components are the intent-capture surface — the place where a visit becomes a signal worth acting on:
| Component | Captures |
|---|---|
ConvertForm | Email / lead capture → /api/v1/webhook |
ConvertExternal | Outbound clicks (Stripe, LemonSqueezy, Cal.com) |
ConvertInternal | Internal CTA clicks |
ConvertPricing | Pricing interaction |
ConvertSocial | Social profile clicks |
ConvertSocialShare | Share actions |
ConvertRss | Feed subscriptions (rss module) |
Three layouts ship: default, article, landing — selected per route with an
appLayout route rule.
Environment
| Variable | Purpose |
|---|---|
NUXT_SIGNAL_EXPORT_TOKEN | Bearer token for GET /api/_signals/export. Unset → 503. |
NUXT_PUBLIC_SITE_ID | Site identifier stamped on every row. Defaults to the request host. |
NUXT_PUBLIC_SITE_URL | Canonical site URL, consumed by @nuxtjs/seo. |
That is the signal surface in full. A third signal env var means a feature that does not capture signal.
Module options (nuxt.config.ts)
events: {
signals: {
enabled: true, // signal capture on/off
capacity: 170_000, // ring buffer size (14 days)
captureErrors: true, // client errors → the stream
},
debug: true, // echo events to the console in dev
}
layer/ The Nuxt layer — published as @incubrain/foundry
app/ Components, composables, layouts, pages
modules/ events (signal capture), rss, markdown-rewrite, config, css
server/ MCP tools, content API, caching
examples/foundry/ Reference app — the one to copy
playground/ Test harness (unit + nuxt + e2e specs)
deploy/ vercel.website.json (Dockerfile in examples/foundry)
pnpm dev # layer dev server
pnpm dev:foundry # example app
pnpm test # vitest (specs live in playground/test)
pnpm verify # lint + typecheck
pnpm build # build the layer
Releasing is documented in RELEASING.md.
Validation is not product. These are out, and staying out:
MIT