Skip to content

Commit 346cdc2

Browse files
committed
feat: Added action, package-managers, tart, terraform, ollama, and files. Added new skill for generating examples
1 parent 900441a commit 346cdc2

13 files changed

Lines changed: 426 additions & 16 deletions

File tree

.claude/commands/add-examples.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# add-examples
2+
3+
Add `defaultConfig` and `exampleConfigs` to a Codify resource.
4+
5+
## Instructions
6+
7+
The user will either pass a file path as an argument (`$ARGUMENTS`) or have a file open in the IDE. Read the resource file, then follow the rules below to add `defaultConfig` and `exampleConfigs`.
8+
9+
If `$ARGUMENTS` is provided, use that file path. Otherwise use the file the user has open.
10+
11+
### Step 1 — Read the resource
12+
13+
Read the resource file. Identify:
14+
- The config interface/type (fields, which are required vs optional)
15+
- `operatingSystems` declared in `getSettings()` — determines whether to add `os` to examples
16+
- `dependencies` — used to decide whether to show a multi-resource example
17+
- Any existing `defaultConfig` or `exampleConfigs` (update rather than duplicate)
18+
19+
If the schema is a separate JSON file, read it too.
20+
21+
Also check for sibling resources that are commonly used together (e.g. if this resource `dependsOn` another type, read that type's file to understand its config shape).
22+
23+
### Step 2 — Add `defaultConfig`
24+
25+
Rules:
26+
- Type: `Partial<TheConfig>` (never include `os` — it's not on the typed config interface)
27+
- For required fields with no sensible default: use the placeholder string `'<Replace me here!'>`
28+
- For optional arrays that default to empty: set to `[]`
29+
- Omit fields that are purely user-specific (paths, names, credentials)
30+
- Use the tool's own documented defaults where applicable
31+
32+
### Step 3 — Add `exampleConfigs`
33+
34+
Rules:
35+
- Up to two examples: `example1` and `example2`
36+
- **No trivial examples** — every example must have meaningful configuration, not just `{ type: 'foo' }` with no parameters
37+
- `example1`: the most common real-world use case with substantive config values
38+
- `example2`: a more advanced variant OR a multi-resource example showing full end-to-end setup; multi-resource is preferred when the resource `dependsOn` another
39+
- Every example needs a `title` (short noun-phrase) and a `description` (one sentence)
40+
- Use realistic placeholder values for sensitive fields (`'<Replace me here!'>`), not real credentials
41+
- Do not add step-numbering in descriptions
42+
43+
**`os` field in examples:**
44+
- The `os` field values come from the `ResourceOs` enum in `@codifycli/schemas` (`../codify-schemas/src/types/index.ts`): `'macOS'`, `'linux'`, `'windows'`
45+
- Add `os` to config entries inside examples only when `operatingSystems` is restricted to a single OS (e.g. Darwin-only → `os: ['macOS']`, Linux-only → `os: ['linux']`)
46+
- Skip `os` entirely when the resource supports both Darwin and Linux
47+
48+
**Shared examples:**
49+
- When a multi-resource example is used across multiple related resources (e.g. asdf + asdf-plugin + asdf-install), define it once in a shared `examples.ts` file in the resource folder and spread it in with `...exampleSharedConfigs`
50+
51+
### Step 4 — Import `ExampleConfig`
52+
53+
Add `ExampleConfig` to the existing `@codifycli/plugin-core` import if not already present.
54+
55+
### Step 5 — Register in `getSettings()`
56+
57+
Add `defaultConfig` and `exampleConfigs` fields inside the object returned by `getSettings()`, before `operatingSystems`.
58+
59+
## Output format
60+
61+
Make all edits directly to the file. Do not summarise every line changed — just briefly confirm what was added.

CLAUDE.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -383,16 +383,17 @@ Every resource should have a `defaultConfig` and `exampleConfigs`. These are sur
383383
- For required fields with no sensible default (e.g. `deviceId`, `plugin`, `awsAccessKeyId`), use the placeholder string `'<Replace me here!'>`
384384
- For optional array fields that default to empty (e.g. `plugins`, `aliases`, `paths`), set them to `[]`
385385
- Omit fields that are purely user-specific (e.g. paths, names, credentials) — don't guess
386-
- If the resource declares `operatingSystems: [OS.Darwin]` or `operatingSystems: [OS.Linux]` (i.e. only one OS, not both), do NOT add `os` to `defaultConfig` (it's not on the typed config interface). Instead, add `os: ['darwin']` or `os: ['linux']` only to the config entries inside `exampleConfigs`. Skip entirely when the resource supports both OS.
386+
- If the resource declares `operatingSystems: [OS.Darwin]` or `operatingSystems: [OS.Linux]` (i.e. only one OS, not both), do NOT add `os` to `defaultConfig` (it's not on the typed config interface). Instead, add the correct `os` value only to the config entries inside `exampleConfigs`. Skip entirely when the resource supports both OS.
387+
- The `os` field values come from the `ResourceOs` enum in `@codifycli/schemas` (`../codify-schemas/src/types/index.ts`): use `'macOS'` for Darwin, `'linux'` for Linux, `'windows'` for Windows (e.g. `os: ['macOS']`, not `os: ['darwin']`).
387388

388389
**`exampleConfigs`** — up to two named examples (`example1`, `example2`):
389-
- `example1`: a minimal, focused single-resource example showing the most common use case
390+
- `example1`: a substantive example showing the most common real-world use case with meaningful configuration — not a trivial "just install it" with no parameters
390391
- `example2`: either a more advanced single-resource variant, OR a multi-resource example that shows the full end-to-end setup (e.g. install the tool + configure it)
391392
- Multi-resource examples (configs array with multiple types) are especially useful when the resource `dependsOn` another — show installing the dependency too
392393
- Every example needs a `title` (short, noun-phrase) and a `description` (one sentence explaining what it does and why)
393394
- Use realistic but obviously-placeholder values for sensitive fields (`'<Replace me here!'>`), not real credentials
394395
- Don't add step-numbering ("Step 1 of 3") in descriptions — it doesn't make sense when viewed from a single resource page
395-
- If the resource is OS-specific (only Darwin or only Linux), add `os: ['darwin']` or `os: ['linux']` to each config entry in the example so the editor filters it correctly
396+
- If the resource is OS-specific (only Darwin or only Linux), add the correct `os` value to each config entry in the example so the editor filters it correctly (e.g. `os: ['macOS']`)
396397

397398
**Structure:**
398399
```typescript
@@ -401,7 +402,7 @@ import { ExampleConfig } from '@codifycli/plugin-core';
401402
const defaultConfig: Partial<MyConfig> = {
402403
someField: 'sensible-default',
403404
optionalArray: [],
404-
// Add os: ['darwin'] or os: ['linux'] if operatingSystems is not [OS.Darwin, OS.Linux]
405+
// Add os: ['macOS'] or os: ['linux'] if operatingSystems is not [OS.Darwin, OS.Linux]
405406
}
406407

407408
const exampleBasic: ExampleConfig = {
@@ -410,7 +411,7 @@ const exampleBasic: ExampleConfig = {
410411
configs: [{
411412
type: 'my-resource',
412413
someField: 'example-value',
413-
// Add os: ['darwin'] or os: ['linux'] if the resource is OS-specific
414+
// Add os: ['macOS'] or os: ['linux'] if the resource is OS-specific
414415
}]
415416
}
416417

src/resources/apt/apt.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { CreatePlan, ExampleConfig, Resource, ResourceSettings, SpawnStatus, getPty } from '@codifycli/plugin-core';
2-
import { OS, ResourceConfig, ResourceOs } from '@codifycli/schemas';
2+
import { LinuxDistro, OS, ResourceConfig, ResourceOs } from '@codifycli/schemas';
33

44
import schema from './apt-schema.json';
55
import { AptInstallParameter } from './install-parameter.js';
@@ -11,6 +11,7 @@ export interface AptConfig extends ResourceConfig {
1111

1212
const defaultConfig: Partial<AptConfig> = {
1313
install: [],
14+
distro: [LinuxDistro.DEBIAN_BASED],
1415
os: [ResourceOs.LINUX]
1516
}
1617

@@ -20,6 +21,7 @@ const exampleBasic: ExampleConfig = {
2021
configs: [{
2122
type: 'apt',
2223
os: [ResourceOs.LINUX],
24+
distro: [LinuxDistro.DEBIAN_BASED],
2325
install: ['curl', 'git', 'build-essential'],
2426
}]
2527
}
@@ -29,6 +31,7 @@ const exampleVersionPinned: ExampleConfig = {
2931
description: 'Install packages using apt, with specific versions pinned for reproducibility.',
3032
configs: [{
3133
type: 'apt',
34+
distro: [LinuxDistro.DEBIAN_BASED],
3235
os: [ResourceOs.LINUX],
3336
install: [
3437
'curl',

src/resources/dnf/dnf.ts

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { CreatePlan, Resource, ResourceSettings, SpawnStatus, getPty } from '@codifycli/plugin-core';
2-
import { OS, ResourceConfig } from '@codifycli/schemas';
1+
import { CreatePlan, ExampleConfig, getPty, Resource, ResourceSettings, SpawnStatus } from '@codifycli/plugin-core';
2+
import { LinuxDistro, OS, ResourceConfig, ResourceOs } from '@codifycli/schemas';
33

44
import schema from './dnf-schema.json';
55
import { DnfInstallParameter, DnfPackage } from './install-parameter.js';
@@ -9,11 +9,47 @@ export interface DnfConfig extends ResourceConfig {
99
update?: boolean;
1010
}
1111

12+
const defaultConfig: Partial<DnfConfig> = {
13+
install: [],
14+
distro: [LinuxDistro.RPM_BASED],
15+
os: [ResourceOs.LINUX]
16+
}
17+
18+
const exampleBasic: ExampleConfig = {
19+
title: 'Install common dev tools with dnf',
20+
description: 'Install a set of frequently needed development packages on a Fedora/RHEL-based system.',
21+
configs: [{
22+
type: 'dnf',
23+
install: ['git', 'curl', 'wget', 'vim', 'make'],
24+
distro: ['rpm-based'],
25+
os: ['linux'],
26+
}]
27+
}
28+
29+
const examplePinned: ExampleConfig = {
30+
title: 'Install packages at pinned versions',
31+
description: 'Install specific versions of packages to ensure a reproducible development environment across machines.',
32+
configs: [{
33+
type: 'dnf',
34+
install: [
35+
{ name: 'nodejs', version: '20.0.0' },
36+
{ name: 'python3', version: '3.11.0' },
37+
],
38+
distro: ['rpm-based'],
39+
os: ['linux'],
40+
}]
41+
}
42+
1243
export class DnfResource extends Resource<DnfConfig> {
1344

1445
override getSettings(): ResourceSettings<DnfConfig> {
1546
return {
1647
id: 'dnf',
48+
defaultConfig,
49+
exampleConfigs: {
50+
example1: exampleBasic,
51+
example2: examplePinned,
52+
},
1753
operatingSystems: [OS.Linux],
1854
schema,
1955
parameterSettings: {

src/resources/file/file.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { CreatePlan, DestroyPlan, ModifyPlan, ParameterChange, Resource, ResourceSettings, z } from '@codifycli/plugin-core';
1+
import { CreatePlan, DestroyPlan, ExampleConfig, ModifyPlan, ParameterChange, Resource, ResourceSettings, z } from '@codifycli/plugin-core';
22
import { OS } from '@codifycli/schemas';
33
import fs from 'node:fs/promises';
44
import path from 'node:path';
@@ -18,10 +18,41 @@ const schema = z.object({
1818

1919
type FileConfig = z.infer<typeof schema>;
2020

21+
const defaultConfig: Partial<FileConfig> = {
22+
path: '<Replace me here!>',
23+
contents: '',
24+
}
25+
26+
const exampleDotfile: ExampleConfig = {
27+
title: 'Manage a dotfile with declarative contents',
28+
description: 'Create and keep a configuration file in sync with the exact contents specified — useful for dotfiles like .curlrc or .wgetrc.',
29+
configs: [{
30+
type: 'file',
31+
path: '~/.curlrc',
32+
contents: '--silent\n--location\n--retry 3\n',
33+
}]
34+
}
35+
36+
const exampleOnlyCreate: ExampleConfig = {
37+
title: 'Bootstrap a file only if it does not exist',
38+
description: 'Write an initial .env file on first run without overwriting any local edits made afterwards.',
39+
configs: [{
40+
type: 'file',
41+
path: '~/.config/myapp/.env',
42+
contents: 'API_URL=https://api.example.com\nDEBUG=false\n',
43+
onlyCreate: true,
44+
}]
45+
}
46+
2147
export class FileResource extends Resource<FileConfig> {
2248
getSettings(): ResourceSettings<FileConfig> {
2349
return {
2450
id: 'file',
51+
defaultConfig,
52+
exampleConfigs: {
53+
example1: exampleDotfile,
54+
example2: exampleOnlyCreate,
55+
},
2556
operatingSystems: [OS.Darwin, OS.Linux],
2657
schema,
2758
parameterSettings: {

src/resources/file/remote-file.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
CodifyCliSender,
33
CreatePlan,
44
DestroyPlan,
5+
ExampleConfig,
56
ModifyPlan,
67
ParameterChange,
78
RefreshContext,
@@ -27,10 +28,41 @@ export interface FileConfig extends ResourceConfig{
2728
onlyCreate: boolean;
2829
}
2930

31+
const defaultConfig: Partial<FileConfig> = {
32+
path: '<Replace me here!>',
33+
remote: '<Replace me here!>',
34+
}
35+
36+
const exampleSync: ExampleConfig = {
37+
title: 'Sync a dotfile from Codify cloud',
38+
description: 'Pull a remote file stored in Codify cloud and write it to a local path, keeping it in sync on every apply.',
39+
configs: [{
40+
type: 'remote-file',
41+
path: '~/.zshrc',
42+
remote: 'codify://<Replace me here!>:<Replace me here!>',
43+
}]
44+
}
45+
46+
const exampleOnlyCreate: ExampleConfig = {
47+
title: 'Bootstrap a config file from Codify cloud without overwriting',
48+
description: 'Write the file on first apply only - subsequent applies skip it, so manual local edits are preserved.',
49+
configs: [{
50+
type: 'remote-file',
51+
path: '~/.config/myapp/settings.json',
52+
remote: 'codify://<Replace me here!>:<Replace me here!>',
53+
onlyCreate: true,
54+
}]
55+
}
56+
3057
export class RemoteFileResource extends Resource<FileConfig> {
3158
getSettings(): ResourceSettings<FileConfig> {
3259
return {
3360
id: 'remote-file',
61+
defaultConfig,
62+
exampleConfigs: {
63+
example1: exampleSync,
64+
example2: exampleOnlyCreate,
65+
},
3466
operatingSystems: [OS.Darwin, OS.Linux],
3567
allowMultiple: true,
3668
schema,

src/resources/ollama/ollama.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
CreatePlan,
3+
ExampleConfig,
34
FileUtils,
45
Resource,
56
ResourceSettings,
@@ -27,10 +28,37 @@ const schema = z
2728

2829
export type OllamaConfig = z.infer<typeof schema>;
2930

31+
const defaultConfig: Partial<OllamaConfig> = {
32+
models: [],
33+
}
34+
35+
const exampleBasic: ExampleConfig = {
36+
title: 'Install Ollama with a model',
37+
description: 'Install the Ollama runtime and pull a model to run locally.',
38+
configs: [{
39+
type: 'ollama',
40+
models: ['llama3.2'],
41+
}]
42+
}
43+
44+
const exampleMultiModel: ExampleConfig = {
45+
title: 'Install Ollama with multiple models',
46+
description: 'Install Ollama and pull several models for local use, including a coding-focused and a general-purpose model.',
47+
configs: [{
48+
type: 'ollama',
49+
models: ['llama3.2', 'mistral', 'qwen2.5-coder'],
50+
}]
51+
}
52+
3053
export class OllamaResource extends Resource<OllamaConfig> {
3154
getSettings(): ResourceSettings<OllamaConfig> {
3255
return {
3356
id: 'ollama',
57+
defaultConfig,
58+
exampleConfigs: {
59+
example1: exampleBasic,
60+
example2: exampleMultiModel,
61+
},
3462
operatingSystems: [OS.Darwin, OS.Linux],
3563
schema,
3664
dependencies: ['homebrew'],

src/resources/scripting/action.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { CreatePlan, DestroyPlan, getPty, Resource, ResourceSettings, SpawnStatus } from '@codifycli/plugin-core';
1+
import { CreatePlan, DestroyPlan, ExampleConfig, getPty, Resource, ResourceSettings, SpawnStatus } from '@codifycli/plugin-core';
22
import { RefreshContext } from '@codifycli/plugin-core/src/resource/resource.js';
33
import { OS, StringIndexedObject } from '@codifycli/schemas';
44

@@ -10,11 +10,40 @@ export interface ActionConfig extends StringIndexedObject {
1010
cwd?: string;
1111
}
1212

13+
const defaultConfig: Partial<ActionConfig> = {
14+
action: '<Replace me here!>',
15+
}
16+
17+
const exampleConditional: ExampleConfig = {
18+
title: 'Run a script only when a condition is met',
19+
description: 'Execute a setup command only when the target directory does not already exist, making the action idempotent.',
20+
configs: [{
21+
type: 'action',
22+
condition: '[ ! -d ~/.config/myapp ]',
23+
action: 'mkdir -p ~/.config/myapp && cp /etc/myapp/defaults.conf ~/.config/myapp/config.conf',
24+
}]
25+
}
26+
27+
const exampleCwd: ExampleConfig = {
28+
title: 'Run a project setup script in a specific directory',
29+
description: 'Run a post-clone initialisation script from within a project directory after dependencies are installed.',
30+
configs: [{
31+
type: 'action',
32+
action: 'make bootstrap',
33+
cwd: '~/projects/myapp',
34+
}]
35+
}
36+
1337
export class ActionResource extends Resource<ActionConfig> {
14-
38+
1539
getSettings(): ResourceSettings<ActionConfig> {
1640
return {
1741
id: 'action',
42+
defaultConfig,
43+
exampleConfigs: {
44+
example1: exampleConditional,
45+
example2: exampleCwd,
46+
},
1847
operatingSystems: [OS.Darwin, OS.Linux],
1948
schema,
2049
parameterSettings: {

0 commit comments

Comments
 (0)