Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
cf472cf
docs(agents): add CWL-ENTRY read-first block
seonghobae Sep 2, 2026
fb2c244
test(governance): pin canonical LLM owner guidance RED
seonghobae Sep 3, 2026
45f115d
chore(governance): run bounded guidance source repair
seonghobae Sep 3, 2026
dae59c4
ci(governance): remove stalled temporary guidance repair workflow
seonghobae Sep 3, 2026
853f7a6
docs(governance): align Claude LLM authority boundary
seonghobae Sep 3, 2026
75e6c09
docs(governance): preserve frontend guidance wording
seonghobae Sep 3, 2026
6ca9879
docs(governance): align agent LLM authority boundary
seonghobae Sep 3, 2026
a2b0a31
docs(governance): restore complete AGENTS guidance after bounded edit
seonghobae Sep 3, 2026
a8c3503
docs(governance): codify canonical model owner boundary
seonghobae Sep 4, 2026
d1a0cbd
test(governance): require OpenCode orchestrator boundary
seonghobae Sep 4, 2026
c249658
fix(governance): route OpenCode through orchestrator free
seonghobae Sep 4, 2026
57254cb
docs(agents): make repository entry verifiable
seonghobae Sep 4, 2026
4c31028
merge: stack verifiable agent entry
seonghobae Sep 4, 2026
f038377
test(docs): pin architecture LLM owner boundary
seonghobae Sep 5, 2026
0907cb1
docs(architecture): align LLM owner boundary
seonghobae Sep 7, 2026
1261c32
docs(agents): preserve verified smoke and delivery know-how
seonghobae Sep 8, 2026
c54c005
docs(agents): record smoke API and startup evidence boundaries
seonghobae Sep 8, 2026
a3421f3
fix(deps): bump next to 16.3.4 and sharp override to 0.35.4
seonghobae Sep 9, 2026
d76f7b4
test(security): lock frontend patched dependency floors
seonghobae Sep 9, 2026
a5abe04
test(deps): reproduce weak frontend lock validation
seonghobae Sep 9, 2026
e8a54fc
fix(deps): validate frontend lock security floors structurally
seonghobae Sep 9, 2026
a34c17c
merge: adopt frontend security prerequisite for agent entry
seonghobae Sep 9, 2026
2938080
merge: restack LLM governance on security-admitted entry
seonghobae Sep 9, 2026
88467c0
chore(review): use central OpenCode configuration
seonghobae Sep 9, 2026
0d7f52e
docs(review): stack central OpenCode consumer on governance owner
seonghobae Sep 9, 2026
19d54c3
test(review): narrow central OpenCode consumer contract
seonghobae Sep 9, 2026
09500e4
fix(review): keep OpenCode config owner-controlled
seonghobae Sep 9, 2026
9b19ced
chore(review): restore canonical release and gap writers
seonghobae Sep 9, 2026
b97f42f
fix(deps): raise frontend audit security floors
seonghobae Sep 9, 2026
09cb87a
test(deps): bind js-yaml owner succession structurally
seonghobae Sep 9, 2026
532229b
chore(agents): restack entry contract on current security owner
seonghobae Sep 9, 2026
f58cbeb
chore(governance): restack LLM authority on current entry prerequisite
seonghobae Sep 9, 2026
53ec33c
chore(review): restack central-config consumer on current governance …
seonghobae Sep 9, 2026
a275901
docs(agents): preserve customer-copy boundary
seonghobae Sep 9, 2026
8928037
chore(review): restack #1625 on current #1549
seonghobae Sep 9, 2026
a6715c9
test(deps): reproduce missing Vitest lock-entry gap
seonghobae Sep 9, 2026
21897d8
test(deps): require Vitest lock resolutions
seonghobae Sep 9, 2026
83b302a
chore(stack): adopt current frontend security contract
seonghobae Sep 9, 2026
9696075
chore(stack): adopt current repository-entry prerequisite
seonghobae Sep 9, 2026
27a59ae
chore(stack): adopt current Naruon governance prerequisite
seonghobae Sep 9, 2026
15fecaa
test(security): reproduce Vitest importer drift
seonghobae Sep 9, 2026
17a7618
test(security): bind Vitest importer contract
seonghobae Sep 9, 2026
2bcf5eb
chore(stack): adopt current security owner
seonghobae Sep 9, 2026
1c343aa
chore(stack): adopt current entry prerequisite
seonghobae Sep 9, 2026
7bfc7ca
chore(stack): adopt current governance prerequisite
seonghobae Sep 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 78 additions & 35 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# AGENTS.md

<!-- CWL-ENTRY -->
> **Agents: read the master context FIRST.** Before any work, read:
>
> - [`docs/architecture/naruon-product-spec.md`](docs/architecture/naruon-product-spec.md) for product vision, architecture, RBAC/ABAC, core features, AI agent ontology, branding/UX, observability, and governance;
> - the live [GitHub Project #1](https://github.com/orgs/ContextualWisdomLab/projects/1), the work and roadmap source of truth;
> - [`docs/product-technical-gap-baseline.md`](docs/product-technical-gap-baseline.md), the live gap snapshot but not merge authorization, and canonical completion issue [#1428](https://github.com/ContextualWisdomLab/naruon/issues/1428);
> - `ContextualWisdomLab/.github`'s [`docs/agent-github-project-protocol.md`](https://github.com/ContextualWisdomLab/.github/blob/main/docs/agent-github-project-protocol.md) for Project operation; and
> - `ContextualWisdomLab/.github`'s [`docs/product-goal-directive.md`](https://github.com/ContextualWisdomLab/.github/blob/main/docs/product-goal-directive.md) before running or configuring the continuous PR review→fix→merge→develop loop. A length-capped `/goal` pointer does not replace the full directive.
>
> This repository's Figma file ID is not yet canonical on `develop`: ADR-0013 and file ID `68b5XB58w8nwT2LYOOnikK` remain Proposed in open PR [#1436](https://github.com/ContextualWisdomLab/naruon/pull/1436). The repository and Project, not private agent memory, are authoritative.

<!-- BEGIN cwl-agent-guidance -->
## Agent guidance (CWL governance)

Expand Down Expand Up @@ -136,35 +147,23 @@ in this repo.
`.github/workflows/opencode-review.yml`, `.github/workflows/strix.yml`,
`.github/workflows/strix-selftest.yml`, or
`.github/workflows/pr-review-merge-scheduler.yml`.
- The central Strix Security Scan uses GitHub Models by default through
`STRIX_GITHUB_MODELS_TOKEN`, `STRIX_LLM=openai/gpt-5`, and
`LLM_API_BASE_FILE` pointing at a trusted file containing
`https://models.github.ai/inference`; GitHub Models scans must try the
configured GPT-5-or-newer model first and may fall back to the explicit
workflow fallback list, currently
`github_models/deepseek/deepseek-r1-0528` and
`github_models/deepseek/deepseek-v3-0324`, when GitHub Models provider
capacity or model availability blocks the primary run. The Strix gate must
route these fallback names through the GitHub Models endpoint with
OpenAI-compatible child model names such as
`openai/deepseek/deepseek-r1-0528`, not the public DeepSeek API. Do not use
GPT-4.1 or weaker GitHub Models fallbacks for Strix or OpenCode PR review
evidence. Keep the GitHub Models endpoint in a trusted input file and pass
the token only through
the provider-scoped Strix child-process key path. Legacy `STRIX_LLM` secrets
must not override PR, push, or scheduled Strix defaults. Vertex remains
available only for manual
`workflow_dispatch` evidence when the `strix_llm` input
explicitly selects `vertex_ai/gemini-3.1-pro-preview-customtools` or
`vertex_ai/gemini-2.5-flash` with `GCP_SA_KEY`; expose Google/Vertex
credentials only for Vertex provider mode. Direct OpenAI GPT-5.4-or-newer
scans remain supported only for manual `strix_llm` selections with
`STRIX_OPENAI_API_KEY`. Do not silently fall back between providers, and
do not treat timeout-class provider infrastructure failures as clean PR
evidence even when Strix printed zero vulnerabilities before failing. Disable
silent Vertex fallback models in the workflow unless a future PR proves a new
exact fallback contract with no Timeout/Fatal/Warn/Denied output. Record
provider evidence in the PR. Known third-party Strix/Pydantic
- Central model-backed Actions are owned by `ContextualWisdomLab/.github` and
request only the logical `orchestrator/free` pool with a gateway token. Thin
callers in this repository must not select or forward provider names, model
names, provider groups, endpoints, or paid fallback credentials.
- `ContextualWisdomLab/contextual-orchestrator` owns provider discovery,
capability-based routing, free-pool membership, and fallback. Naruon owns
product/domain truth, authorization, tools, and context assembly. Production
use requires an immutable released owner API/client/schema; verify protected
release evidence before adoption and fail closed when that contract or a
required capability is unavailable. Do not copy owner source, query owner
storage, or treat an open PR or unreleased branch as a consumable contract.
- Do not impose a shared application/agent/gateway wall-clock timeout on model
work. A configured administrator limit, explicit user cancellation, or the
upstream provider's terminal result may end it; reasoning, streaming, and
tool calls are not failed merely because elapsed time is long.
- A failed model-backed check remains failed evidence even when an intermediate
report printed zero findings. Known third-party Strix/Pydantic
serializer warnings must be filtered narrowly inside the Strix gate child
process, not as a visible workflow env entry, so Warn-class logs are not
accepted as clean evidence and warning-filter variable names do not pollute
Expand Down Expand Up @@ -274,6 +273,19 @@ in this repo.

## Workspace and task tracking defaults

- Browser smoke must check collected console and page errors after interaction,
accessibility, screenshot capture, and page cleanup, not only after navigation.
Keep the early check for fast failure and a final check before returning success.
Regression tests must inject late errors into the actual route-smoke execution;
a successful screenshot or a passing render assertion does not prove clean interactions.
If screenshot retries are exhausted, throw the capture failure; do not create
diagnostic text files in the temporary capture directory or count them as screenshots.
Close the page in a finally block, including navigation and capture failures.
- Browser-smoke API mocks must reject unregistered requests with a non-success
response and record a harness failure even when the UI suppresses the error.
Cover requests emitted during cleanup; never return a default `{ ok: true }`.
Keep request URLs, query values, and payloads out of failure diagnostics.

- First-run frontend sessions should open the Today execution dashboard while
preserving explicit Dashboard, Email, and Calendar startup choices.
- Workspace navigation changes must keep the desktop primary nav and the
Expand Down Expand Up @@ -457,10 +469,10 @@ in this repo.
update both backend header tests and frontend link tests. Global backend
responses must include `Referrer-Policy`, and `target="_blank"` links must
use explicit `rel="noopener noreferrer"`.
- When robot review cites an obsolete Strix provider policy, update the docs and
tests to the current GitHub Models default contract before accepting a
rollback suggestion; do not reintroduce generic `LLM_API_KEY` or
cross-provider credential forwarding while trying to satisfy old comments.
- When robot review cites obsolete provider-specific Strix policy, compare it
with the released `.github` and `contextual-orchestrator` contracts before
accepting a rollback suggestion. Do not reintroduce direct-provider routing,
generic provider credentials, or cross-provider credential forwarding.
- When reviews find inert navigation/dead-space controls, either wire them to an
implemented workspace route/API or remove the control; do not leave
high-traffic drawer/sidebar entries as permanent `준비 중` copy.
Expand Down Expand Up @@ -568,6 +580,10 @@ in this repo.
browser-submitted relationship classifications. Route layers should derive the
thread provenance server-side, persist only scoped ontology metadata, and keep
provider writes out of relationship capture.
- Relationship UI must derive customer wording from the bounded `next_action`
contract and must not render raw `action_reason`, provider rationale, source
keys, or machine action names. Unknown actions use a neutral next-step message;
browser coverage must assert both the customer text and absence of raw fields.
- Unique email and forwarded-import dedupe must use strong scoped signals:
normalized Message-ID, References/In-Reply-To, persisted duplicate provenance,
or exact body/attachment fingerprints. Do not merge threads from subject-only
Expand Down Expand Up @@ -649,12 +665,39 @@ in this repo.

## Development environment and tooling defaults

- Read the applicable repository skill before changing its contract:
[fix-development-mistakes](.agents/skills/fix-development-mistakes/SKILL.md)
for failures and security findings,
[github-actions-privileged-pr-scan](.agents/skills/github-actions-privileged-pr-scan/SKILL.md)
for privileged PR scanners, and
[github-robot-review-gate](.agents/skills/github-robot-review-gate/SKILL.md)
for check/review diagnosis. Record the failing reproduction, smallest causal
repair, exact verification command, and remaining gates in the existing PR.
- Visual Inspection requires opening the actual rendered pages or captured
images, not merely counting PNG files. Record app/build SHA separately from
runner SHA, viewport, routes, and observed defects. Mocked browser evidence
does not prove live provider behavior, all locales, or deployment readiness.
Inspect the changed AGENTS.md rendering on the pushed revision as well.
- A server-ready timeout before browser navigation is failed startup evidence,
not a completed visual inspection. Record the exact source and execution result;
host load alone does not prove the cause or justify increasing test timeouts.
- Preserve concurrent commits with ordinary history integration, then verify
the combined tree before pushing. Update these instructions with reusable
failure-prevention lessons; keep dated findings in the gap baseline/PR.
- Package registry credentials alone do not authorize or configure a cluster
deployment. Use the existing release workflow only after its protected-source,
checks, target credentials, and destination prerequisites are verified; report
package publication and live deployment as separate outcomes.
- Before relocating guidance out of a PR, verify its complete successor delta
and record the destination PR, commit, and path; a named owner alone is not succession.
- If CodeGraph is not initialized for this repository, agents may run
`codegraph init -i` autonomously without asking first; keep generated
`.codegraph/` and `.cursor/rules/codegraph.mdc` artifacts local unless a
future repository policy explicitly says to commit them. OpenCode PR review
uses the project `opencode.jsonc` MCP servers for CodeGraph, DeepWiki,
Context7, and web search. It must initialize CodeGraph before review so
receives the only `opencode.jsonc` from the central required workflow; do not
add repository-local `opencode.json` or `opencode.jsonc`. The central owner
registers review MCP servers, including Graphify. It must initialize
CodeGraph before review so
structural findings cite graph-backed evidence instead of relying only on grep
or raw file reads; use Context7 for current library docs, DeepWiki for
repository documentation, and web search only for bounded external lookups.
Expand Down
67 changes: 41 additions & 26 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
flowchart LR
UI[Next.js frontend] --> API[FastAPI backend / Naruon control plane]
API --> DB[(Postgres + pgvector)]
API --> LLM[OpenAI APIs when configured]
API --> LLM[contextual-orchestrator released consumer API]
API --> CONN[Outbound-only self-hosted connector]
CONN --> MAIL[Customer IMAP/POP3/SMTP]
CONN --> DAV[Customer CalDAV/CardDAV/WebDAV]
Expand All @@ -20,6 +20,15 @@ Runtime database connectivity is secret-injected: `backend/core/config.py` has
no fallback `DATABASE_URL`, so missing database configuration fails at startup
rather than silently using shared development credentials.

Production LLM work crosses an immutable released `contextual-orchestrator`
API/client/schema. `contextual-orchestrator` owns provider discovery,
capability-based routing, free-pool membership, and provider fallback; Naruon
owns product/domain truth, authorization, tools, and context assembly. A missing
or incompatible released owner contract fails closed instead of creating a
Naruon-local provider/model fallback. Local deterministic fixtures and legacy
provider surfaces may remain for migration/testing only when they are explicitly
identified as non-production authority.

## Topic-intelligence boundary

Naruon has no live Structural Topic Modeling endpoint, fitted topic artifact,
Expand Down Expand Up @@ -83,7 +92,10 @@ registry/list/update/delete plus prompt-preview provider selection paths filter
the authenticated organization. Existing local databases get the same fail-closed
owner backfill through `scripts/bootstrap_db.py`; legacy provider rows require
explicit non-default `NARUON_IMPORT_USER_ID` and `NARUON_IMPORT_ORGANIZATION_ID`
before bootstrap will set the new columns non-null.
before bootstrap will set the new columns non-null. This table and its direct
provider-routing fields are legacy migration surfaces, not the production
provider/model authority; new production LLM work must consume the released
`contextual-orchestrator` contract instead of extending this registry as a router.

`ticket_tasks` stores email-derived execution items as ticket-like work records.
The table and its new columns use at least two-word `snake_case` database names
Expand Down Expand Up @@ -170,13 +182,15 @@ ETag/If-Match-guarded CalDAV/WebDAV PUT local adapter handlers for
`SelfHostedConnector`; packaging, registration-token lifecycle, backend
dispatch, and non-DAV protocol adapters remain separate connector delivery work.

LLM provider `base_url` is also a server-side egress boundary, not an arbitrary
URL field. Provider registry create/update paths are organization-admin scoped,
and LLM call sinks validate custom OpenAI-compatible base URLs with HTTPS-only
syntax, no userinfo/query or fragment, exact host membership in
`ALLOWED_LLM_BASE_URL_HOSTS`, and DNS answers that are all globally routable.
Missing allowlist configuration fails closed; the default provider path should
leave `base_url` unset.
The legacy LLM-provider `base_url` path remains a server-side egress boundary
while migration is incomplete, not an arbitrary URL field or production routing
authority. Existing provider registry create/update paths remain
organization-admin scoped, and current call sinks retain HTTPS-only syntax,
userinfo/query/fragment rejection, exact `ALLOWED_LLM_BASE_URL_HOSTS` membership,
and globally routable DNS validation until the legacy path is removed. Missing
allowlist configuration still fails closed. New production model work must not
select a provider endpoint through this surface; it uses the immutable released
`contextual-orchestrator` consumer contract.

## Batch embedding routing boundary

Expand All @@ -192,12 +206,13 @@ SSRF-guarded, allowlisted, pinned-address HTTP client
(`build_llm_provider_http_client`) that fronts every other outbound LLM call.
naruon records a durable `llm_batch_jobs` / `llm_batch_items` audit trail
(routing mode, the orchestrator's batch id, reported cost) for observability.
The path degrades gracefully: if batching is disabled, the orchestrator base URL
is rejected by the egress guard, or the orchestrator is unreachable, the caller
transparently falls back to the per-item embedding path. A local `pg-llm-batch`
package/checkout remains only as an optional offline-dev fallback, gated behind
orchestrator-unavailable and an explicit local DSN; naruon does not vendor a
gitlink for that fallback in this PR.
The currently implemented per-item fallback is migration behavior rather than
canonical provider authority: if batching is disabled or the orchestrator path
cannot be used, callers may still reach the legacy per-item embedding path, but
that path must not grow new production provider/model selection. A local
`pg-llm-batch` package/checkout remains only as an optional offline-dev fallback,
gated behind orchestrator-unavailable and an explicit local DSN; naruon does not
vendor a gitlink for that fallback in this PR.

## Semantic project-graph extractor seam

Expand All @@ -216,16 +231,16 @@ and the runner degrades down the chain instead of losing the projection. New
extractors (including future plugins on the platform plan's `kg.extractor`
extension point) register a selector without editing ingest.

Routing LLM extraction through **contextual-orchestrator** is modelled as a
transport concern: the orchestrator is an OpenAI-compatible gateway, so the
`orchestrator` selector reuses the identical grounded LLM extractor
(`extract_project_semantics_llm`, which enforces segment citations) but points
its SSRF-allowlisted client (`build_llm_provider_http_client`) at
`PROJECT_GRAPH_ORCHESTRATOR_BASE_URL` instead of the raw provider. The provider
API key stays the tenant's Fernet-encrypted credential, and the orchestrator base
URL must be HTTPS and exact-host allowlisted by `ALLOWED_LLM_BASE_URL_HOSTS`;
an unset or rejected endpoint fails closed to the deterministic extractor. Design
and grounding: [`docs/architecture/kg-extractor-seam.md`](docs/architecture/kg-extractor-seam.md).
The current `orchestrator` selector still reuses the grounded LLM extractor and
an OpenAI-compatible transport adapter, but that compatibility layer is legacy
migration plumbing rather than Naruon-owned provider/model routing. It points the
SSRF-allowlisted client (`build_llm_provider_http_client`) at
`PROJECT_GRAPH_ORCHESTRATOR_BASE_URL`; its existing credential and allowlist
handling remains in place until the released owner client replaces it. New
production behavior must consume the immutable released `contextual-orchestrator`
API/client/schema and must not add raw-provider fallback here. An unset or
rejected endpoint fails closed to the deterministic extractor. Design and
grounding: [`docs/architecture/kg-extractor-seam.md`](docs/architecture/kg-extractor-seam.md).

## CI security boundary

Expand Down Expand Up @@ -319,4 +334,4 @@ target source id, but it must not provide source ownership or capability records
`backend/api/calendar.py` obtains writeback sources through a FastAPI dependency
that reads DB-backed `calendar_writeback_sources` records scoped to the
authenticated user. Provider execution remains opt-in and fail-closed without an
active outbound runner or If-Match/ETag evidence.
active outbound runner or If-Match/ETag evidence.
Loading