Skip to content
Back to skills

Implement

ASecurity

Implements any code change in the ELPS codebase. This is the foundation skill — all other skills reference its patterns.

  • 36 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 12, 2026
testinggoexpresstestinggit

Works with

  • cli

Security analysis

A100/100

Scanned September 29, 2026

npx -y skills add luthersystems/elps --skill implement --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Implement?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Implement
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/luthersystems-implement/badge)](https://www.skillsdirectory.com/skills/luthersystems-implement)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
# /implement — Code Change Skill

Implements any code change in the ELPS codebase. This is the foundation skill — all other skills reference its patterns.

## Trigger

Use when asked to implement a feature, fix a bug, add a builtin, modify the parser, update the formatter, add CLI flags, update docs, or make any other code change.

## Workflow

### 1. Classify the Change

Determine the change type to know which files to touch:

| Type | Primary Files | Test Pattern |
|------|--------------|--------------|
| `builtin` | `lisp/builtins.go` (`langBuiltins`) | `elpstest.TestSuite` in a topical `lisp/*_test.go` (e.g. `math_test.go`) |
| `special-op` | `lisp/op.go` (`langSpecialOps`) | `elpstest.TestSuite` in a topical `lisp/*_test.go` |
| `macro` | `lisp/macro.go` (`langMacros`) | `elpstest.TestSuite` in `lisp/macro_test.go` or a topical file |
| `linter` | `lint/analyzers.go`, `lint/lint.go` | `lint/lint_test.go` (use `/add-linter-check` skill) |
| `elpsvet` | `cmd/elpsvet/` | `go test ./cmd/elpsvet/` (use `/elpsvet` skill) |
| `fuzz` | `<pkg>/fuzz_test.go`, `internal/fuzzseed/` | `make fuzz` (use `/fuzz` skill) |
| `stdlib` | `lisp/lisplib/lib<name>/` | `elpstest.Runner` + `.lisp` test file (use `/add-stdlib-package` skill) |
| `cli` | `cmd/<command>.go` | Manual verification or integration tests |
| `formatter` | `formatter/formatter.go` | `formatter/formatter_test.go` (`TestASTPreservation`, `TestRepoFileRoundTrip`) |
| `parser` | `parser/rdparser/parser.go`, `parser/lexer/` | `parser/rdparser/parser_test.go` |
| `diagnostic` | `diagnostic/diagnostic.go`, `diagnostic/renderer.go` | `diagnostic/renderer_test.go` |
| `bug-fix` | Varies — find the root cause first | Regression test reproducing the bug |
| `docs` | `docs/lang.md` (embedded), `docs/templates.md`, `docs/embed.md`, `docs/minify.md`, `docs/lint-checks.md`, `AGENTS.md`, skills | `./elps doc --guide` to verify rendering of embedded guides |
| `deps` | `go.mod`, `go.sum` | `make test` to verify compatibility |
| `ci` | `.github/workflows/*.yml` | Push and verify Actions run |
| `profiler` | `lisp/x/profiler/` | Profiler-specific tests |

### 2. Read Before Writing

Where to find the existing patterns for each kind of change:

- For builtins: read nearby entries in `langBuiltins` (`lisp/builtins.go`) and their `builtinXxx` functions
- For ops: read `langSpecialOps` in `lisp/op.go` for the `opXxx` naming convention
- For macros: read `langMacros` in `lisp/macro.go` for the `macroXxx` patterns
- For linter: read existing analyzers in `lint/analyzers.go`
- For stdlib: read an existing package like `lisp/lisplib/libmath/`

### 3. Implement

Follow these rules for all ELPS code:

#### Go Implementation Rules

- **Function signature**: `func builtinXxx(env *lisp.LEnv, args *lisp.LVal) *lisp.LVal`
- **Formals**: `Formals("a", "b")`; modifiers are plain symbols — `Formals("a", OptArgSymbol, "b")` (`&optional`), `VarArgSymbol` (`&rest`), `KeyArgSymbol` (`&key`). Formals are untyped: check `args.Cells[i].Type` in the body and return `env.Errorf(...)` on a mismatch
- **Error propagation**: Return `env.Error("message")` or `env.Errorf("format", args...)`. Errors are `*LVal` values with `Type == LError`, NOT Go `error` interface
- **Check errors**: After any call that returns `*LVal`, check `if v.Type == lisp.LError { return v }` to propagate
- **Docstrings are mandatory**: CI runs `elps doc -m` and fails if any builtin/op/macro lacks a docstring
- **Registration**: Add a `{"name", Formals(...), fn, `docstring`}` entry to `langBuiltins`, `langSpecialOps`, or `langMacros` (returned by `DefaultBuiltins()` / `DefaultSpecialOps()` / `DefaultMacros()`)

#### Lisp Code Rules

- `set` creates bindings. `set!` mutates existing bindings. First binding MUST use `set`
- No backtick reader syntax — write `(quasiquote ...)` / `(unquote ...)`
- `true` and `false` are symbols, not special forms
- `()` is nil/falsey, everything else is truthy
- Keywords start with `:` (e.g., `:key-name`)
- Qualified symbols use `:` separator (e.g., `math:pi`)

#### Adding a builtin, special operator, or macro

1. Implement it in `lisp/builtins.go`, `lisp/op.go`, or `lisp/macro.go`.
2. Give it a docstring in the definition — CI runs `elps doc -m`.
3. If the form has structural requirements (e.g. `rethrow` only inside
   `handler-bind`), add a lint analyzer (`/add-linter-check`).
4. Update `docs/lang.md` if user-facing (it is embedded and served by
   `elps doc --guide`).
5. Write Go and/or lisp tests (below), then `/verify`.

#### Static migration diagnostics

When a correctness fix changes previously accepted behavior, ship a reliable
static diagnostic for recognizable affected source patterns: `elps lint` for
Lisp source (`/add-linter-check`), `elpsvet` for Go embedding or
implementation invariants (`/elpsvet`). Point at the affected expression,
explain the replacement, and test both the broken pattern and valid
lookalikes. Where dynamic bindings, runtime data or opaque macros prevent a
complete check, document the limits — never present a partial check as proof
that a program is compatible.

### 4. Write Tests

#### For builtins/ops/macros — `elpstest.TestSuite`

Each row is a positional `{expression, expected-result, expected-output}`
triple; an expected error is written as its rendered message:

```go
func TestMyBuiltin(t *testing.T) {
	tests := elpstest.TestSuite{
		{"my-builtin", elpstest.TestSequence{
			{`(my-builtin "arg1" 42)`, `"expected-result"`, ""},
			{`(my-builtin)`, "test:1:1: lisp:my-builtin: invalid number of arguments: 0", ""},
		}},
	}
	elpstest.RunTestSuite(t, tests)
}
```

#### For linter checks — See `/add-linter-check` skill

#### For stdlib packages — See `/add-stdlib-package` skill

#### For bug fixes — Write a regression test that:
1. Fails without the fix (verify this first)
2. Passes with the fix

### 5. Branch Naming

Create a branch before starting work:
- Features: `feature/<short-description>`
- Bug fixes: `fix/<short-description>`
- Refactors: `refactor/<short-description>`
- Issue-driven: `issue-<N>/<short-description>`

Never commit or push to `main`; the `/pr` skill has the guard.

### 6. Verify

After implementation, run the full verification pipeline. See `/verify` skill.

## Checklist

- [ ] Read target files before modifying
- [ ] Implementation follows existing code style
- [ ] Docstring included (if adding builtin/op/macro)
- [ ] Tests written (regression test for bug fixes)
- [ ] `make test` passes
- [ ] `make static-checks` passes
- [ ] `./elps doc -m` passes (if touching builtins)
- [ ] `docs/lang.md` updated (if user-facing feature)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.