diff --git a/.opencode/commands/implement-plan.md b/.opencode/commands/implement-plan.md
index 20eedb3fe5..8ecd1bd537 100644
--- a/.opencode/commands/implement-plan.md
+++ b/.opencode/commands/implement-plan.md
@@ -3,11 +3,8 @@ description: Execute a ready plan end-to-end — create a GitHub issue, branch i
agent: build
---
-# Implement Plan
-
This command is run once a plan is ready (for example, from plan mode). Execute
-the plan already prepared in the current session context — it does not take
-extra arguments. Follow these steps in order.
+the plan already prepared in the current session context. Follow these steps in order.
## 1. Create the issue
diff --git a/.opencode/commands/review.md b/.opencode/commands/review.md
deleted file mode 100644
index 70bd89ac90..0000000000
--- a/.opencode/commands/review.md
+++ /dev/null
@@ -1,25 +0,0 @@
-Act as a senior software engineer and perform a thorough review.
-
-## Instructions
-
-1. **Determine what is being reviewed** from the provided context:
- - **If it is a plan** (implementation plan, design document, task breakdown) → load the **`plan-review`** skill.
- - **If it is code** (diff, PR, code change) → load the **`code-review`** skill.
-
-2. Read `AGENTS.md` and follow its instructions for finding and reading all related testing documentation from memories before reviewing.
-
-3. **Skip generated files, lockfile-only changes, and unrelated modifications** unless they introduce security risks.
-
-4. Follow the loaded skill's process and produce its output format.
-
-## Strong Rules
-
-1. Do not invent problems. Every finding must be real and actionable.
-2. Do not modify any code and do not create a commit — this command only reviews.
-3. Be specific and constructive. "This could be better" is not helpful — explain why and how.
-4. Prioritize by impact. One structural issue outweighs ten nits.
-5. Missing tests are an issue, not a suggestion. Report as a severity-tagged finding — never as a recommendation.
-
-## Context
-
-$ARGUMENTS
diff --git a/.opencode/skills/code-review/SKILL.md b/.opencode/skills/code-review/SKILL.md
index 7f06d90b59..7fa581efa0 100644
--- a/.opencode/skills/code-review/SKILL.md
+++ b/.opencode/skills/code-review/SKILL.md
@@ -106,6 +106,8 @@ For detailed security guidance, see `security-and-hardening`.
| **Low:** | Minor, optional | Author may ignore — formatting, style preferences |
| **Suggestion:** | Worth considering | Not required, but improves the code |
+**Unique finding IDs.** Assign every finding a stable identifier: `F1`, `F2`, `F3`, … numbered in order of severity (Critical first, then High, Medium, Low, Suggestion). Use the ID everywhere the finding is mentioned — in section headers, in the verdict, in follow-up discussion. Never renumber within a review. Example: `**F3 (High)** — `app/validate.cljs:42` — duplicate branch logic…`.
+
For each finding, describe the circumstances under which it could fail: specific inputs, load conditions, timing, or user actions that trigger the problem. "This crashes when input is null" is actionable; "this might crash" is not.
Lead with what matters: correctness and security first, then structural issues, then everything else. A few high-conviction comments beat a long list.
@@ -122,11 +124,11 @@ Briefly explain what the code does and give an overall assessment.
### Critical and High-Priority Issues
-List problems that could cause security incidents, data loss, crashes, incorrect behavior, or major performance degradation. For each: state the severity, identify the file/function/code section, explain why it's a problem, describe failure circumstances, and provide a concrete improvement with corrected code when useful.
+List problems that could cause security incidents, data loss, crashes, incorrect behavior, or major performance degradation. Each finding gets its unique ID (`F1`, `F2`, …). For each: state the severity, identify the file/function/code section, explain why it's a problem, describe failure circumstances, and provide a concrete improvement with corrected code when useful.
### Other Findings
-List medium- and low-priority issues, including maintainability and design concerns.
+List medium- and low-priority issues, including maintainability and design concerns. Continue the ID sequence started above (`F3`, `F4`, …).
### Suggested Refactoring
@@ -148,6 +150,8 @@ Choose one:
- **Approve with minor changes** — Good to merge after addressing low/medium issues
- **Request changes** — Critical or high issues must be resolved before merge
+List the finding IDs the verdict depends on (e.g. "Request changes: F1, F4").
+
## Change Sizing
Small, focused changes are easier to review, faster to merge, and safer to deploy.
@@ -231,25 +235,13 @@ For supply-chain risk triage, follow the `security-and-hardening` skill.
## Verification
-After review is complete:
+Before emitting the verdict, verify the change as it stands. This is the reviewer's own due diligence — it covers the state of the code at review time, not the later resolution of findings (fixing findings is the author's job; confirming them is a new review):
-- [ ] All Critical issues are resolved
-- [ ] All Required (no-prefix) changes are resolved or explicitly deferred with justification
-- [ ] Tests pass
+- [ ] Tests pass — run them yourself, don't trust the claim
- [ ] Build succeeds
- [ ] The verification story is documented (what changed, how it was verified)
- [ ] Dependency upgrades reviewed against changelog, isolated per package, verified by green suite
-## Multi-Model Review Pattern
-
-Use different models for different review perspectives:
-
-```
-Model A writes the code → Model B reviews → Model A addresses feedback → Human makes the final call
-```
-
-Different models have different blind spots.
-
## See Also
- For detailed security review guidance, see `security-and-hardening`
diff --git a/.opencode/skills/planner/SKILL.md b/.opencode/skills/planner/SKILL.md
index d1802652e2..3598a0dc16 100644
--- a/.opencode/skills/planner/SKILL.md
+++ b/.opencode/skills/planner/SKILL.md
@@ -1,13 +1,13 @@
---
name: planner
-description: Read-only planning and architecture analysis for Penpot — produce a structured implementation plan (Context, Affected modules, Approach, Risks, Testing). Always output to the user; additionally save to .opencode/plans/YYYY-MM-DD-
.md.
+description: Read-only planning and architecture analysis for Penpot — produce a structured implementation plan with task breakdown, acceptance criteria, sizing, and checkpoints. Always output to the user and save to .opencode/plans/YYYY-MM-DD-.md.
---
# Planner
Read-only senior software architect role for Penpot. Produces structured
-implementation plans that engineers or other agents can execute. Never writes
-or modifies code.
+implementation plans with task breakdowns that engineers or other agents can
+execute. Never writes or modifies code.
## When to Use
@@ -18,24 +18,29 @@ or modifies code.
- The user asks "how would I implement X?" or "what's involved in fixing Y?".
- The user is about to start non-trivial work and wants a bite-sized task
breakdown.
+- A task feels too large or vague to start.
+- Work needs to be parallelized across multiple agents or sessions.
Do **not** use this skill to actually implement anything — it is read-only.
+**When NOT to use:** Single-file changes with obvious scope, or when the spec
+already contains well-defined tasks.
+
## Role
-You are a Senior Software Architect working on Penpot, an open-source design
-tool. Your sole responsibility is planning and analysis — you do NOT write or
-modify code.
+You help users understand the Penpot codebase, design solutions, and produce
+implementation plans that other agents or developers can execute. The plan
+tells them what to build and how to verify it, task by task.
-You help users understand the codebase, design solutions, and create detailed
-implementation plans that other agents or developers can execute. Document
-everything they need to know: which files to touch for each task, code patterns,
-tests, and how to verify correctness. Apply DRY and KISS principles.
+The implementer reads the project's agent docs (`AGENTS.md`, project memories
+such as `mem:critical-info`, `mem:testing`, and each module's core memory)
+before working. Reference those memories instead of re-explaining tooling,
+conventions, or test design — explain in the plan only what they do not cover.
Do **not** suggest commit messages or commit names anywhere in your plans or
-responses — committing is the developer's responsibility.
+responses — committing is the implementer's responsibility.
-## Required Reading Before Planning
+## CRITICAL: Required Reading Before Planning
Before drafting any plan, work through the project's own guidance:
@@ -50,6 +55,8 @@ Before drafting any plan, work through the project's own guidance:
Skipping this step is the #1 cause of incorrect or incomplete plans.
+---
+
## The Planning Process
### Phase 1: Architecture Analysis
@@ -64,16 +71,42 @@ Skipping this step is the #1 cause of incorrect or incomplete plans.
### Phase 2: Task Breakdown
-Implementation order follows the monorepo's dependency graph:
-`frontend -> common`, `backend -> common`, `exporter -> common`,
-`frontend -> render-wasm`. Build shared foundations first, then layer
-consumers on top.
+#### Identify the Dependency Graph
+
+Map what depends on what, following the monorepo's module dependency graph:
+
+```
+common (shared types, schemas — no deps)
+ │
+ ├── backend (depends common)
+ │ ├── RPC handlers
+ │ └── persistence / migrations
+ │
+ ├── frontend (depends common, render-wasm)
+ │ ├── UI components
+ │ └── state / API integration
+ │
+ ├── exporter (depends common)
+ │
+ └── render-wasm (consumed by frontend)
+```
+
+Implementation order follows the dependency graph bottom-up: build shared
+foundations first, then layer consumers on top.
#### Slice Vertically
Instead of building all of common, then all of backend, then all of frontend —
build one complete feature path at a time:
+**Bad (horizontal slicing):**
+```
+Task 1: Build all common types
+Task 2: Build all backend handlers
+Task 3: Build all frontend components
+```
+
+**Good (vertical slicing):**
```
Task 1: common data types + schema ← foundation
Task 2: backend RPC handler + persistence
@@ -89,39 +122,58 @@ Each task follows this structure:
```markdown
## Task [N]: [Short descriptive title]
-**Description:** One paragraph explaining what this task accomplishes.
+**Description:** One or two paragraphs explaining what this task accomplishes.
+Should be clear and concise.
+
+**Rationale:** Why this task exists and why this approach over the obvious
+alternatives — design decisions, trade-offs, constraints discovered during
+analysis. One or two sentences; skip only if genuinely trivial.
+
+**Code sketch (optional):** Signature-, type-, or shape-level example when the
+intended interface is non-obvious. Keep it short — a skeleton that fixes the
+contract (function signature, model fields, error shape), never a full
+implementation. Omit when the task is mechanical.
**Acceptance criteria:**
- [ ] [Specific, testable condition]
- [ ] [Specific, testable condition]
**Verification:**
-- [ ] Tests pass (module-specific test command)
-- [ ] Lint/formatter passes (module-specific check command)
+- [ ] Relevant tests pass (module-specific test command).
+- [ ] Lint/formatter passes (module-specific check command), if applicable.
+- [ ] The core flow works end-to-end, if applicable.
**Dependencies:** [Task numbers this depends on, or "None"]
**Files likely touched:**
- `path/to/file.clj`
- `path/to/file_test.clj`
+
+**Estimated scope:** [XS: 1 file | S: 1-2 files | M: 3-5 files | L: 5+ files]
```
Replace "module-specific test command" with the actual commands for the module
-(e.g. `clojure -M:dev:test` for backend/common, `npx shadow-cljs compile test && npx karma start` for frontend,
-or the commands noted in the module's core memory).
+(e.g. `clojure -M:dev:test` for backend/common,
+`npx shadow-cljs compile test && npx karma start` for frontend, or the
+commands noted in the module's core memory).
+
+When possible, design each task with TDD in mind: acceptance criteria double
+as a test list, and the natural first step of the task is writing those tests
+before the implementation. Some tasks resist this (config, migrations, pure
+wiring) — for those, keep the usual verification steps.
#### Estimate Scope
-| Size | Files | Scope |
-|------|-------|-------|
-| **XS** | 1 | Single function, config change, or schema tweak |
-| **S** | 1-2 | One handler or component method |
-| **M** | 3-5 | One vertical feature slice |
-| **L** | 5-8 | Multi-component feature |
-| **XL** | 8+ | **Too large — break it down further** |
+| Size | Files | Scope | Example |
+|------|-------|-------|---------|
+| **XS** | 1 | Single function, config change, or schema tweak | Add a validation rule |
+| **S** | 1-2 | One handler or component method | Add a new RPC endpoint |
+| **M** | 3-5 | One vertical feature slice | Bookmark CRUD with tests |
+| **L** | 5-8 | Multi-component feature | Search with filtering and pagination |
+| **XL** | 8+ | **Too large — break it down further** | — |
-If a task is L or larger, break it into smaller tasks. Agents perform best on
-S and M tasks.
+If a task is XL, it should be broken into smaller tasks. Agents perform best
+on S and M tasks.
**When to break a task down further:**
- It would take more than one focused session
@@ -141,11 +193,11 @@ Arrange tasks so that:
Add explicit checkpoints with the relevant module commands:
```markdown
-## Checkpoint: After Tasks 1-3
-- [ ] All tests pass (module-specific command)
-- [ ] Lint/format passes (module-specific command)
-- [ ] Core flow works end-to-end
-- [ ] Review with human before proceeding
+### Checkpoint: After Tasks 1-3
+- [ ] Relevant tests pass (module-specific command).
+- [ ] The relevant build or compilation passes, if applicable.
+- [ ] The core flow works end-to-end.
+- [ ] Review with human before proceeding.
```
## Requirements
@@ -159,7 +211,7 @@ Add explicit checkpoints with the relevant module commands:
- Apply DRY and KISS principles to the proposed implementation.
- Define a testing strategy aligned with each affected module's tooling.
- Every task must have acceptance criteria and verification steps.
-- Checkpoints must exist between major phases.
+- Checkpoints must exist after every 2-3 tasks.
## Constraints
@@ -168,7 +220,8 @@ Add explicit checkpoints with the relevant module commands:
`.opencode/plans/`.
- You do **not** run builds, tests, linters, or any commands that modify state.
- You do **not** create git commits or interact with version control.
-- You do **not** execute shell commands beyond read-only searches.
+- You do **not** execute shell commands beyond read-only searches (`rg`, `ls`,
+ `find`, `cat`, `bat`).
- Your output is a structured plan or analysis, ready for handoff to an
engineer agent or developer.
@@ -188,8 +241,9 @@ slug is lowercase, hyphen-separated, and a short summary of the task
(e.g. `add-batch-get-profiles-for-file-comments`). Create the
`.opencode/plans/` directory if it does not exist.
-Always attempt the write. If the user explicitly provides a target file path,
-use that path instead of the default.
+IMPORTANT: The plan agent has write permission specifically for
+`.opencode/plans/` — always attempt the write. If the user explicitly provides
+a target file path, use that path instead of the default.
### Plan Document Template
@@ -212,41 +266,75 @@ use that path instead of the default.
security implications.]
## Approach
-[Step-by-step implementation plan with file paths, function names, and code
-shape where applicable. Group steps into atomic, ordered tasks.]
+[A short strategy summary: 3-5 sentences describing the overall approach and
+the shape of the dependency graph (what depends on what, what gets built
+first). High-level only — the task-by-task detail lives in the Task List.]
## Task List
-### Phase 1: Foundation
-- [ ] Task 1: ...
-- [ ] Task 2: ...
+Each task uses the full task structure defined in
+[Write Tasks](#write-tasks) — description, rationale, acceptance criteria,
+verification, dependencies, files, estimated scope, and optional code sketch.
+Never reduce a task to a one-line checkbox; the plan must be self-contained
+and executable without other context.
-### Checkpoint: Phase 1
-- [ ] Tests pass, lint/formatter clean (module-specific commands)
+Tasks are a flat, ordered list — a plan is not a roadmap. Do not group tasks
+into phases, milestones, or sprints; ordering and dependencies are already
+captured per task. Insert a checkpoint after every 2-3 tasks.
-### Phase 2: Core Features
-- [ ] Task 3: ...
-- [ ] Task 4: ...
+## Task 1: [Short descriptive title]
-### Checkpoint: Phase 2
-- [ ] End-to-end flow works
+**Description:** [What this task accomplishes.]
-### Phase 3: Polish
-- [ ] Task 5: ...
-- [ ] Task 6: ...
+**Rationale:** [Why this approach over the alternatives.]
-### Checkpoint: Complete
-- [ ] All acceptance criteria met
-- [ ] Ready for review
+**Acceptance criteria:**
+- [ ] [Specific, testable condition]
-## Testing Strategy
-[How to verify: which test commands to run per module, what cases to cover,
-manual verification steps, lint/format checks. Consult each module's core
-memory for the exact commands.]
+**Verification:**
+- [ ] Relevant tests pass (module-specific command).
+
+**Dependencies:** None
+
+**Files likely touched:**
+- `path/to/file`
+
+**Estimated scope:** [XS: 1 file | S: 1-2 files | M: 3-5 files | L: 5+ files]
+
+**Code sketch (optional):** [Short contract-level example, only if the shape
+is non-obvious.]
+
+## Task 2: [Short descriptive title]
+
+[Same structure as Task 1.]
+
+## Task 3: [Short descriptive title]
+
+[Same structure as Task 1.]
+
+### Checkpoint: After Tasks 1-3
+- [ ] Relevant tests pass (module-specific command).
+- [ ] The relevant build or compilation passes, if applicable.
+- [ ] The core flow works end-to-end.
+- [ ] Review with human before proceeding.
+
+## Task 4: [Short descriptive title]
+
+[Same structure as Task 1.]
+
+## Task 5: [Short descriptive title]
+
+[Same structure as Task 1.]
+
+## Verification & Testing
+[How to verify each task and the whole plan: the project's real test, lint,
+build, and run commands (extracted during Required Reading), coverage
+expectations, and manual checks. Consult each module's core memory for the
+exact commands.]
## Parallelization Opportunities
- **Safe to parallelize:** Independent feature slices across separate
- modules, tests for already-implemented features
+ modules, tests for already-implemented features, documentation
- **Must be sequential:** Shared common schema changes, database migrations
- **Needs coordination:** Features that share a contract (define the contract
first, then parallelize)
@@ -259,13 +347,31 @@ When the plan is purely analytical (e.g. a code review or feasibility study
with no implementation), skip the **Approach** and **Task List** sections and
lead with **Findings** instead, keeping the rest of the structure.
+## Common Rationalizations
+
+| Rationalization | Reality |
+|---|---|
+| "I'll figure it out as I go" | That's how you end up with a tangled mess and rework. 10 minutes of planning saves hours. |
+| "The tasks are obvious" | Write them down anyway. Explicit tasks surface hidden dependencies and forgotten edge cases. |
+| "Planning is overhead" | Planning is the task. Implementation without a plan is just typing. |
+| "I can hold it all in my head" | Context windows are finite. Written plans survive session boundaries and compaction. |
+
+## Red Flags
+
+- Delivering prose without a task breakdown
+- Tasks that say "implement the feature" without acceptance criteria
+- No verification steps in the plan
+- All tasks are XL-sized
+- No checkpoints between tasks
+- Dependency order isn't considered
+
## Verification Checklist
-Before starting implementation, confirm:
+Before delivering the plan, confirm:
- [ ] Every task has acceptance criteria
- [ ] Every task has a verification step
- [ ] Task dependencies are identified and ordered correctly
-- [ ] No task touches more than ~5 files
-- [ ] Checkpoints exist between major phases
-- [ ] The human has reviewed and approved the plan
+- [ ] No task is XL or larger — break it down instead
+- [ ] Checkpoints exist after every 2-3 tasks
+- [ ] The plan is ready for human review
diff --git a/.serena/memories/devenv/core.md b/.serena/memories/devenv/core.md
index 0651f872fe..db46542c99 100644
--- a/.serena/memories/devenv/core.md
+++ b/.serena/memories/devenv/core.md
@@ -6,6 +6,7 @@ Compose-based dev environment under `docker/devenv/`, driven by `manage.sh`. Par
- `penpotdev-infra`: shared `postgres`, `minio`, `minio-setup`, `mailer`, `ldap`. File: `docker-compose.infra.yml`.
- `penpotdev-wsN` (N=0,1,…): per-instance `main` + `redis` (Valkey). File: `docker-compose.main.yml`. ws0 (a.k.a. `main`) binds `$PWD`; ws1+ bind clones at `${PENPOT_WORKSPACES_DIR}/wsN/` (default `~/.penpot/penpot_workspaces/`), maintained by the developer.
+- Optional overlay `docker-compose.opencode.yml`: added by `instance-compose` as an extra `-f` only when `PENPOT_OPENCODE_CONFIG_DIR` is set (i.e. `run-devenv --opencode-config-dir DIR` ran in this process). Bind-mounts the host dir at `/home/penpot/.config/opencode` (`:z`). Flag-only, per-call; not read from ambient env. Parser `parse-opencode-config-dir` absolutizes (`~`, realpath) because compose resolves relative bind sources against the compose file's dir. Only instances brought up with the flag get the mount.
- All projects join external network `penpot_shared`. Created idempotently by `ensure-devenv-network`, never removed by lifecycle commands.
## Source-of-truth files
@@ -65,7 +66,7 @@ No `--delete` on the working-tree pass: gitignored caches in the workspace survi
## CLI surface
-- `run-devenv --agentic [--ws main|0|wsN|N] [--sync] [--serena-context CTX]`: bring one instance up. Agentic only — MCP and Serena windows are always created. Default target main. Errors out if the target is already running. `--sync` is rejected on main; on ws1+ it's optional (forced only when the workspace dir does not exist yet).
+- `run-devenv --agentic [--ws main|0|wsN|N] [--sync] [--serena-context CTX] [--opencode-config-dir DIR]`: bring one instance up. Agentic only — MCP and Serena windows are always created. Default target main. Errors out if the target is already running. `--sync` is rejected on main; on ws1+ it's optional (forced only when the workspace dir does not exist yet). `--opencode-config-dir DIR` bind-mounts DIR at `~/.config/opencode` in-container via the optional overlay above; mount applies at container creation, so changing it requires stop + re-run.
- `stop-devenv [--ws main|0|wsN|N] [--all]`: stop instances. Flags mutually exclusive. `--ws N` stops just that workspace. `--ws 0` or no flag stops ws0; shared infra shuts down only if no other instances remain. `--all` stops every ws highest-first then ws0, then infra.
- `run-devenv`: legacy alias, ws0 non-agentic attached.
- `attach-devenv [--ws main|0|wsN|N]`: pure attach. Fails fast if instance/session missing.
diff --git a/backend/src/app/rpc/management/nitrate.clj b/backend/src/app/rpc/management/nitrate.clj
index 9dc140ba4a..a470f2451e 100644
--- a/backend/src/app/rpc/management/nitrate.clj
+++ b/backend/src/app/rpc/management/nitrate.clj
@@ -1045,3 +1045,18 @@ RETURNING id, deleted_at;")
(update acc :created conj email)))))
{:created [] :skipped []}
emails)))))
+
+;; ---- API: get-air-gapped
+
+(def ^:private schema:get-air-gapped-result
+ [:map
+ [:air-gapped ::sm/boolean]])
+
+(sv/defmethod ::get-air-gapped
+ "Returns whether this Penpot instance runs in air-gapped mode."
+ {::doc/added "2.18"
+ ::sm/params [:map]
+ ::sm/result schema:get-air-gapped-result
+ ::rpc/auth false}
+ [_cfg _params]
+ {:air-gapped (contains? cf/flags :air-gapped-conf)})
diff --git a/backend/test/backend_tests/rpc_management_nitrate_test.clj b/backend/test/backend_tests/rpc_management_nitrate_test.clj
index aabf58f31d..da78b2e733 100644
--- a/backend/test/backend_tests/rpc_management_nitrate_test.clj
+++ b/backend/test/backend_tests/rpc_management_nitrate_test.clj
@@ -194,6 +194,15 @@
(string? (get version k)))))
(t/is (= cf/version version))))
+(t/deftest get-air-gapped
+ (let [out (th/management-command! {::th/type :get-air-gapped})]
+ (t/is (th/success? out))
+ (t/is (false? (-> out :result :air-gapped))))
+ (binding [cf/flags (conj cf/flags :air-gapped-conf)]
+ (let [out (th/management-command! {::th/type :get-air-gapped})]
+ (t/is (th/success? out))
+ (t/is (true? (-> out :result :air-gapped))))))
+
(t/deftest get-teams-returns-only-owned-non-default-non-deleted
(with-mocks [nitrate-mock {:target 'app.nitrate/call :return nil}]
(let [profile (th/create-profile* 1 {:is-active true})
diff --git a/docker/devenv/docker-compose.opencode.yml b/docker/devenv/docker-compose.opencode.yml
new file mode 100644
index 0000000000..1af29e3749
--- /dev/null
+++ b/docker/devenv/docker-compose.opencode.yml
@@ -0,0 +1,10 @@
+# Optional compose overlay, included by manage.sh's instance-compose ONLY
+# when PENPOT_OPENCODE_CONFIG_DIR is set (run-devenv --opencode-config-dir
+# DIR). Bind-mounts a host directory over the container's opencode global
+# config dir (~/.config/opencode) so personal agents/prompts/skills kept in
+# a separate repo are available inside the devenv without committing them
+# here. Without the flag this file is never referenced.
+services:
+ main:
+ volumes:
+ - "${PENPOT_OPENCODE_CONFIG_DIR}:/home/penpot/.config/opencode:z"
diff --git a/docs/technical-guide/developer/agentic-devenv.md b/docs/technical-guide/developer/agentic-devenv.md
index 55b03c1492..932f555d6f 100644
--- a/docs/technical-guide/developer/agentic-devenv.md
+++ b/docs/technical-guide/developer/agentic-devenv.md
@@ -148,10 +148,15 @@ automatically, so regular users never run this.
```bash
./manage.sh run-devenv --agentic \
[--ws N] [--sync] [--serena-context CTX] \
+ [--opencode-config-dir DIR] \
[--git-user-name NAME] [--git-user-email EMAIL]
```
Brings one agentic instance up. Errors out if the target is already running.
+`--opencode-config-dir DIR` bind-mounts DIR over the container's
+`~/.config/opencode` so personal agents/prompts/skills kept in a separate
+repository are available to the coding agent; see the
+[Dev environment guide](./devenv.md#personal-opencode-config-inside-the-container).
`--ws N` (N ≥ 1) brings that workspace up independently — workspaces can be
started and stopped in any order. Per-instance ports
diff --git a/docs/technical-guide/developer/devenv.md b/docs/technical-guide/developer/devenv.md
index 922ed24f1d..d6cc65e89a 100644
--- a/docs/technical-guide/developer/devenv.md
+++ b/docs/technical-guide/developer/devenv.md
@@ -139,6 +139,27 @@ until you set an identity. The values are applied every time
`run-devenv` brings an instance up (idempotent), so re-running
with different flags is the way to change the in-container identity.
+### Personal opencode config inside the container
+
+`run-devenv --opencode-config-dir DIR` bind-mounts a host directory over the
+container's `~/.config/opencode` (opencode's global config dir). This is how
+you keep personal agents, prompts, and skills in a separate repository and
+use them inside the devenv without committing them here or leaving untracked
+files in the repo:
+
+```bash
+./manage.sh run-devenv --agentic --opencode-config-dir ../penpot-opencode
+```
+
+The path must be an existing directory; `~` is expanded and the value is
+resolved to an absolute path automatically. The mount is applied at container
+creation, so changing it requires stopping and re-running `run-devenv` for
+that instance, and it applies only to instances brought up with the flag —
+other workspaces mount nothing. The directory is shared read-write with the
+container (same UID mapping as the source tree). Opencode's own state
+(sessions, `auth.json`) lives in `~/.local/share/opencode`, which stays in
+the container's data volume regardless of this flag.
+
### Shared state and workers
All instances share one Penpot database and one MinIO bucket; users, teams,
diff --git a/frontend/src/app/main/ui/auth.cljs b/frontend/src/app/main/ui/auth.cljs
index 790d8b0a3e..a77457c70c 100644
--- a/frontend/src/app/main/ui/auth.cljs
+++ b/frontend/src/app/main/ui/auth.cljs
@@ -13,7 +13,7 @@
[app.main.ui.auth.login :refer [login-page*]]
[app.main.ui.auth.recovery :refer [recovery-page*]]
[app.main.ui.auth.recovery-request :refer [recovery-request-page*]]
- [app.main.ui.auth.register :refer [register-page* register-success-page* register-validate-page* terms-register*]]
+ [app.main.ui.auth.register :refer [register-page* register-success-page* register-validate-page* terms-service-privacy-policy*]]
[app.main.ui.ds.foundations.assets.raw-svg :refer [raw-svg*] :as raw-svg]
[app.main.ui.ds.foundations.typography.heading :refer [heading*]]
[app.util.dom :as dom]
@@ -74,7 +74,7 @@
[:> recovery-page* {:params params}])
(when (= section :auth-register)
- [:> terms-register*])]]))
+ [:> terms-service-privacy-policy*])]]))
(mf/defc auth-page*
diff --git a/frontend/src/app/main/ui/auth.scss b/frontend/src/app/main/ui/auth.scss
index 7d593ce4fa..0462f23514 100644
--- a/frontend/src/app/main/ui/auth.scss
+++ b/frontend/src/app/main/ui/auth.scss
@@ -6,6 +6,7 @@
@use "ds/_sizes.scss" as *;
@use "ds/_utils.scss" as *;
+@use "./ds/mixins.scss" as *;
.auth-section {
display: grid;
@@ -26,6 +27,8 @@
}
.auth-section.register {
+ @include custom-scrollbar;
+
display: flex;
justify-content: center;
align-items: center;
diff --git a/frontend/src/app/main/ui/auth/common.scss b/frontend/src/app/main/ui/auth/common.scss
index 951ea442a6..066b6849d0 100644
--- a/frontend/src/app/main/ui/auth/common.scss
+++ b/frontend/src/app/main/ui/auth/common.scss
@@ -4,56 +4,15 @@
//
// Copyright (c) KALEIDOS INC Sucursal en España SL
-@use "ds/_utils.scss" as *;
@use "ds/_sizes.scss" as *;
@use "ds/_borders.scss" as *;
@use "ds/typography.scss" as *;
-.auth-form-wrapper {
- inline-size: 100%;
- padding-block-end: 0;
- display: grid;
+.form {
+ display: flex;
+ flex-direction: column;
gap: var(--sp-m);
-
- // Native