Install
$ agentstack add skill-zig999-siegard-code-u-fe-development ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
SKILL: Development
Required context
The following variables must be resolved by the Orchestrator before this skill is consumed. If any variable is absent, stop and request it before proceeding.
required_context:
- name: SESSIONS_DIR
source: orchestrator-core (injected at activation)
used_in: delivery file path, backend-pending-items path, backlog.md update
- name: SESSION
source: orchestrator-core (injected at activation)
used_in: same as SESSIONS_DIR
- name: SPECS_DIR
source: orchestrator-core (injected at activation)
used_in: design-system tokens path
> Validation rule: before executing any step that writes to $SESSION_DIR/ or reads from $SPECS_DIR/, confirm the variables are resolved strings (not literal placeholders). If they are still placeholders, emit status: blocked / reason: unresolved_context_variables and halt.
Purpose
This skill defines how the Developer Agent must structure, name, organize, and deliver code — ensuring consistency across Task Contracts and predictability for the QA Agent.
Customization via CLAUDE.md
> Precedence rule defined in orchestrator-core.md. Not repeated here.
Before creating any file, extract from CLAUDE.md:
| What to look for | Used in | |---|---| | Project folder structure | Where to create new files | | Naming conventions | File, class, and function names | | Testing framework/library | How to write and run tests | | Configured logger | Replace console.log | | Custom error pattern | Error classes to extend | | Already defined environment variables | Avoid hardcoding and duplicates | | Global CSS file path (design tokens) | Before implementing any component cataloged in design-system/components.md, check whether base classes already exist for it (buttons, inputs, cards). If they do, use them — do not reimplement states (hover, focus, active, disabled) inline in the component. |
If CLAUDE.md does not cover a given point, use the defaults from this skill and document the decision in the delivery file.
> Design system rule: defining visual tokens (colors, spacing, typography) in component files is forbidden. Always use Tailwind utility classes generated from the design system tokens (bg-surface, text-content, rounded-md, p-lg, duration-fast, ease-out). var(--token-name) is only allowed for dynamic inline values with no equivalent Tailwind utility — this is the exception, not the pattern.
Design system loading routing
The Orchestrator selects which files to load based on exec_type and TC content. Machine-readable routing table:
design_system_routing:
always_load:
- "{SPECS_DIR}/front/design-system-rules.md" # `tc_involves_layout_or_effects`, `tc_modifies_cataloged_component`, `tc_affects_colors_spacing_typography`, `tc_involves_animation_or_a11y` are boolean flags evaluated by the Orchestrator from the TC `objective` and `acceptance_criteria` fields before activation. Full mounting logic: `.claude/agents/dev/protocols/u-fe-context-mounting-developer.md`.
---
## Progress reporting (mandatory)
Emit `task_progress` at each checkpoint before proceeding to the next phase of work. These events reset the stale detection timer and give the orchestrator visibility during long-running tasks.
```bash
# Checkpoint 1 — after reading and validating the task spec
python3 .claude/skills/orch-log/scripts/append.py \
--agent $ORCH_WORKER_ID --event-type task_progress \
--task-id $ORCH_TASK_ID --attempt $ORCH_ATTEMPT \
--data '{"phase":"dev","checkpoint":"spec_validated"}'
# Checkpoint 2 — after analysis, before writing any code
python3 .claude/skills/orch-log/scripts/append.py \
--agent $ORCH_WORKER_ID --event-type task_progress \
--task-id $ORCH_TASK_ID --attempt $ORCH_ATTEMPT \
--data '{"phase":"dev","checkpoint":"analysis_complete"}'
# Checkpoint 3 — after creating the branch, before first file write
python3 .claude/skills/orch-log/scripts/append.py \
--agent $ORCH_WORKER_ID --event-type task_progress \
--task-id $ORCH_TASK_ID --attempt $ORCH_ATTEMPT \
--data '{"phase":"dev","checkpoint":"branch_created"}'
# Checkpoint 4 — after all source code is written, before tests
python3 .claude/skills/orch-log/scripts/append.py \
--agent $ORCH_WORKER_ID --event-type task_progress \
--task-id $ORCH_TASK_ID --attempt $ORCH_ATTEMPT \
--data '{"phase":"dev","checkpoint":"implementation_done"}'
# Checkpoint 5 — after tests are written, before delivery.md
python3 .claude/skills/orch-log/scripts/append.py \
--agent $ORCH_WORKER_ID --event-type task_progress \
--task-id $ORCH_TASK_ID --attempt $ORCH_ATTEMPT \
--data '{"phase":"dev","checkpoint":"tests_written"}'
Never skip a checkpoint. If $ORCH_WORKER_ID, $ORCH_TASK_ID, or $ORCH_ATTEMPT are unresolved, stop and emit task_failed with reason: unresolved_context_variables, retryable: false.
Terminal event guarantee (mandatory)
Before stopping for any reason — tool failure, blocked state, unexpected error, context limit — verify that a terminal event (task_completed or task_failed) has been emitted for $ORCH_TASK_ID / $ORCH_ATTEMPT.
If no terminal has been emitted, emit task_failed immediately before stopping:
python3 .claude/skills/orch-log/scripts/append.py \
--agent $ORCH_WORKER_ID --event-type task_failed \
--task-id $ORCH_TASK_ID --attempt $ORCH_ATTEMPT \
--data '{"phase":"dev","reason":"","retryable":true}'
| Situation | reason | retryable | |-----------|--------|-----------| | Tool call denied or failed | tool_failure | true | | Required file not found | missing_input: | false | | Implementation blocked by ambiguity | blocked_ambiguity | false | | Context limit approaching | context_limit | true | | Unresolved env variables | unresolved_context_variables | false | | Any other unexpected stop | unexpected_exit | true |
The on_subagent_stop hook synthesizes task_failed if this rule is not followed, but explicit emission is always preferred — it carries an accurate reason and retryable flag.
Mandatory flow before coding
Decision order — resolve before writing any component
Stop at the first step that resolves the need:
- Before writing any UI markup, inspect the DS primitive layer (
components/ui/, perCLAUDE.md). If an equivalent primitive exists (Card, Badge, Table, Form…), use it by composition — never reimplement it by hand (u-fe-standards §2.2 Primitive reuse; anti-patternreimplemented-primitive). Thedesign-system/components.mdcatalog is the source of truth for which primitives are cataloged. - Is there an equivalent component in the project's component library (declared in
CLAUDE.md)? Add and use it. - Is there a semantic token for the value? Use the token — never the raw value.
- Is there a similar feature/entity already implemented? Follow the same pattern.
- Does the change respect the project's architecture rules (dependency direction, no sibling-feature imports)? If not, reorganize before coding.
- Does it respect the accessibility standard declared in
CLAUDE.md(u-fe-standards §4)? If not, fix it before delivering.
Generate only what the Task Contract asks for. Do not create stories, visual-regression, token pipeline, i18n, or ADR unless the Task Contract explicitly requires it.
1. Read the full Task Contract (narrative + all acceptance criteria)
→ emit checkpoint: spec_validated
2. Read the files listed as dependencies in the previous delivery (if any)
2.5 Check component specs — covered in Step 1C (Pre-flight gate). By the time you reach this step, component specs for §7 components must already be confirmed present and read. If Step 1C was not executed, stop and run it now before continuing.
3. Map the interface contracts the Task Contract will touch or create
→ emit checkpoint: analysis_complete
4. Confirm you are on the Task Contract branch the Orchestrator created (feat/TC-XX, fix/TC-XX, or refactor/TC-XX) in your worktree
→ emit checkpoint: branch_created
5. Write the implementation plan as a comment at the top of the first file created
6. Only then begin implementation
→ emit checkpoint: implementation_done (after all source code is written, before tests)
7. Write tests
→ emit checkpoint: tests_written (after tests, before delivery.md)
If any step reveals a blocking ambiguity -> stop, emit task_failed with reason: blocked_ambiguity, retryable: false, and record the ambiguity in the delivery file.
Branch and commits
Branch per Task Contract
The Orchestrator-Dev creates one branch + worktree per Task Contract from main before activating you (SIEGARD-04). Confirm you are on it before any implementation:
feat/TC-XX `CLAUDE.md` conventions take precedence (see precedence rule in orchestrator-core).
---
## TypeScript
- Prefer `type` over `interface` — use `interface` only when extension or implementation is needed (e.g., `implements`, `extends` from third parties)
- Components with more than 3 render conditionals -> extract subcomponents
- `any` is forbidden — use `unknown` + type guard (already covered in prohibitions)
- Derive types from validation schemas with `z.infer` — never hand-maintain a type in parallel with its schema
- Use `satisfies` to check a literal against a type without widening it
- Model mutually exclusive shapes as discriminated unions (a literal discriminant field) — not optional-field bags
- Type assertions (`as`) to silence the compiler are forbidden — narrow with `unknown` + type guards instead (`as const` is the only accepted use)
---
## State management
Each type of state has its place — mixing responsibilities leads to subtle bugs and makes debugging harder.
| State type | Where to manage | Example libraries |
|---|---|---|
| Server data (cache) | Server-state library | React Query, SWR, RTK Query |
| Mutations (server writes) | Server-state library | React Query, SWR |
| Global UI state | Dedicated store | Zustand, Jotai, Redux |
| Local component state | `useState` / `useReducer` | — |
**Forbidden:**
- Using a server-state library to manage UI state (e.g., storing a sidebar toggle in React Query)
- Using a UI store for server data cache (e.g., duplicating API data in Zustand)
> The specific library is a project decision (defined in `CLAUDE.md`). This rule defines the **separation of concerns**, not the tool.
---
## Default folder structure
src/ ├── components/ │ └── ui/ Adapt according to the structure defined in CLAUDE.md.
> DS primitive vs feature-local: the criterion for what belongs in components/ui/ (DS primitive) versus features//components/ (feature-local) is defined in design-system/components.md → "Catalog Membership". Promoting a feature-local component into components/ui/ is a design-system spec change (CR) — the Developer flags the need; it never adds primitives to the catalog ad hoc.
Mandatory tests and quality criteria
> Refer to .claude/skills/u-fe-standards/SKILL.md for the mandatory tests per Task Contract type table and test quality criteria. Tests are part of the delivery — the QA Agent does not write tests; it validates the coverage of the tests you delivered.
Error handling
Every function that can fail must:
- Use explicit error types — avoid
throw new Error("something went wrong") - Differentiate operational errors (expected, e.g., 404 from API) from programming errors (bugs)
- Never silence errors with an empty
catch {} - Propagate context:
throw new Error("fetchUser failed", { cause: err })
// Bad
try {
const data = await fetch("/api/users/" + id).then(r => r.json());
return data;
} catch (e) {
throw new Error("error");
}
// Good
try {
const res = await fetch("/api/users/" + id);
if (!res.ok) throw new ApiError(`fetchUser(${id}) returned ${res.status}`);
return res.json();
} catch (err) {
throw new ApiError(`fetchUser(${id}) failed`, { cause: err });
}
Edge cases
> Refer to the universal checklist and handling patterns in .claude/skills/u-fe-standards/SKILL.md. For every implemented function, handle applicable scenarios and document them in the delivery file.
Security
XSS prevention
- Never use
dangerouslySetInnerHTMLwithout explicit security review and DOMPurify sanitization. - User-generated content rendered as HTML must be sanitized before rendering:
import DOMPurify from 'dompurify';
// Bad
// Good — only when rendering HTML is truly required
- Prefer text rendering over HTML rendering:
{userInput}is safe;dangerouslySetInnerHTMLis not. - Never interpolate user input into
href,src, or event handler strings.
Input handling
- Validate all user inputs at the form/component boundary before sending to the API.
- Use a schema validation library (Zod, Yup) for form inputs — do not write manual type checks.
- Never trust API responses for rendering without type-checking: use
Zod.parse()or equivalent.
Sensitive data
- Never log user PII, tokens, or passwords — not even in development.
- Never store auth tokens in
localStoragewithout an explicit product + security decision documented inCLAUDE.md.
Performance
Memoization
Apply memoization only when a measurable performance problem exists — premature optimization adds complexity without benefit.
| Hook / API | When to use | When NOT to use | |---|---|---| | useMemo | Expensive computation that re-renders frequently with the same inputs | Simple value derivation, string formatting | | useCallback | Callback passed as prop to a memoized child component | Inline handlers in a non-memoized component | | React.memo | Pure component that receives the same props frequently | Component that always receives new reference props |
// Use useMemo for expensive transformations
const sortedItems = useMemo(
() => items.slice().sort(compareFn),
[items, compareFn]
);
// No useMemo needed for trivial derivations
const fullName = `${user.first} ${user.last}`;
Code splitting and lazy loading
- Split routes with
React.lazy+Suspense— never import all pages eagerly. - Heavy libraries (charts, rich text editors, PDF viewers) must be dynamically imported:
const HeavyChart = React.lazy(() => import('./HeavyChart'));
- Apply
Suspensewith a meaningful fallback at the route level and around heavy components.
Bundle size
- Prefer named imports for tree-shaking:
import { format } from 'date-fns'— notimport * as dateFns. - Never import entire icon libraries — import individual icons.
- If a third-party library adds > 50 kB gzipped, justify the addition in the delivery file.
NFR thresholds
If CLAUDE.md defines performance_metrics, note expected impact in the delivery file. QA validates in Phase 3. Default reference thresholds (override via CLAUDE.md):
| Metric | Target | Critical | |---|---|---| | LCP (Largest Contentful Paint) | ≤ 2.5 s | > 4.0 s | | FCP (First Contentful Paint) | ≤ 1.8 s | > 3.0 s | | TTI (Time to Interactive) | ≤ 3.8 s | > 7.3 s | | Initial JS bundle (gzipped) | ≤ 200 kB | > 500 kB |
Error boundaries
Every feature must be wrapped in a React ErrorBoundary at the page/route level to prevent a single component failure from crashing the entire application.
Mandatory wrapping points:
- Each page/route component
- Each independently renderable widget or dashboard section
// pages/product-list/index.tsx
import { ErrorBoundary } from 'react-error-boundary';
export function ProductListPage() {
return (
}>
);
}
Fallback UI rules:
- Must display a user-facing message in domain language — not "Something went wrong".
- Must offer a recovery action (retry, go home, contact support).
- Must log the error to the configured err
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: zig999
- Source: zig999/siegard-code
- License: Apache-2.0
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.