Skip to content

Commit 1ceee44

Browse files
feat: Claude Code personality plugin with mood system and configurable traits
- Add personality injection into system prompt via experimental.chat.system.transform hook - Implement mood state machine with drift algorithm and seeded randomness - Add /mood and /personality commands for runtime configuration - Add setMood and savePersonality tools for programmatic control - Support global and project-scoped personality configurations - Add comprehensive documentation and examples (Rick, Splinter personalities) - Add GitHub Actions workflows for CI/CD and npm publishing - Preserve personality state during session compaction - Include TypeScript strict mode and ESLint configuration
0 parents  commit 1ceee44

26 files changed

Lines changed: 3396 additions & 0 deletions

.github/workflows/pr.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: PR Checks
2+
3+
on:
4+
pull_request:
5+
branches: [main]
6+
push:
7+
branches: [main]
8+
9+
jobs:
10+
check:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- uses: oven-sh/setup-bun@v2
16+
with:
17+
bun-version: latest
18+
19+
- name: Install dependencies
20+
run: bun install
21+
22+
- name: Type check
23+
run: bun run typecheck
24+
25+
- name: Lint
26+
run: bun run lint
27+
28+
- name: Build
29+
run: bun run build

.github/workflows/publish.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Publish to npm
2+
3+
on:
4+
release:
5+
types: [published]
6+
workflow_dispatch:
7+
inputs:
8+
tag:
9+
description: 'npm tag (latest, beta, etc.)'
10+
required: false
11+
default: 'latest'
12+
13+
jobs:
14+
publish:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- uses: oven-sh/setup-bun@v2
20+
with:
21+
bun-version: latest
22+
23+
- name: Install dependencies
24+
run: bun install
25+
26+
- name: Build
27+
run: bun run build
28+
29+
- name: Setup Node.js for npm publish
30+
uses: actions/setup-node@v4
31+
with:
32+
node-version: '22'
33+
registry-url: 'https://registry.npmjs.org'
34+
35+
- name: Publish to npm
36+
run: npm publish --access public --tag ${{ github.event.inputs.tag || 'latest' }}
37+
env:
38+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

.github/workflows/release.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
release:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v4
16+
17+
- uses: oven-sh/setup-bun@v2
18+
with:
19+
bun-version: latest
20+
21+
- name: Install dependencies
22+
run: bun install
23+
24+
- name: Build
25+
run: bun run build
26+
27+
- name: Create GitHub Release
28+
uses: softprops/action-gh-release@v1
29+
with:
30+
generate_release_notes: true
31+
env:
32+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
node_modules
2+
dist
3+
*.log
4+
.DS_Store
5+
.opencode/*
6+
.sisyphus/*

AGENTS.md

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# AGENTS.md - OpenCode Personality Plugin
2+
3+
Guidelines for AI agents working on this codebase.
4+
5+
## Project Overview
6+
7+
An OpenCode plugin that adds configurable personality and mood systems to AI assistants. The plugin injects personality traits into the system prompt and manages a mood state machine that drifts over time.
8+
9+
## Code Style
10+
11+
- **TypeScript**: Strict mode enabled with `noUncheckedIndexedAccess` and `exactOptionalPropertyTypes`
12+
- **Formatting**: Use Prettier defaults (no config file needed)
13+
- **Imports**: Use `.js` extensions for local imports (ESM)
14+
- **Types**: Prefer explicit types for function parameters and return values
15+
- **Null handling**: Use `!` only when value is guaranteed; prefer guards
16+
- **Comments**: Avoid inline comments; use JSDoc for public APIs only
17+
18+
## Architecture
19+
20+
```
21+
src/
22+
├── index.ts # Plugin entry point, hooks registration
23+
├── types.ts # All type definitions
24+
├── config.ts # Config loading, merging, state management
25+
├── mood.ts # Mood drift, scoring functions
26+
├── prompt.ts # Personality prompt builder
27+
├── tools/
28+
│ ├── setMood.ts # setMood tool definition
29+
│ └── savePersonality.ts # savePersonality tool definition
30+
└── commands/
31+
├── mood.ts # /mood command handler
32+
└── personality.ts # /personality command handler
33+
```
34+
35+
## Key Files
36+
37+
| File | Purpose |
38+
|------|---------|
39+
| `src/types.ts` | All exported types - modify here for schema changes |
40+
| `src/config.ts` | Config precedence logic (global + project merge), file I/O |
41+
| `src/mood.ts` | Mood drift algorithm - uses seeded random for testing |
42+
| `src/prompt.ts` | Builds personality section for system prompt |
43+
| `src/index.ts` | Plugin hooks registration, main entry point |
44+
45+
## Plugin Hooks Used
46+
47+
| Hook | Purpose |
48+
|------|---------|
49+
| `experimental.chat.system.transform` | Inject personality into system prompt |
50+
| `experimental.session.compacting` | Preserve personality during compaction |
51+
| `event` | Drift mood after assistant responses |
52+
| `command.execute.before` | Handle `/mood` and `/personality` commands |
53+
54+
## Testing Workflow
55+
56+
1. Run `npm run typecheck` to verify types
57+
2. Run `npm run lint` to check code style
58+
3. Run `npm run build` to verify build
59+
4. Test in OpenCode by updating `opencode.json` to point to `src/index.ts`
60+
61+
## Making Changes
62+
63+
### Adding a New Mood Field
64+
65+
1. Add type to `MoodDefinition` or `MoodConfig` in `src/types.ts`
66+
2. Add default value in `DEFAULT_MOODS` or `DEFAULT_MOOD_CONFIG` in `src/config.ts`
67+
3. Use the field in `src/mood.ts` or `src/prompt.ts`
68+
4. Update README config reference
69+
70+
### Adding a New Command
71+
72+
1. Create handler in `src/commands/`
73+
2. Import and wire up in `src/index.ts` `command.execute.before` hook
74+
3. Register in `opencode.json` command definitions
75+
4. Document in README
76+
77+
### Adding a New Tool
78+
79+
1. Create tool in `src/tools/` using `tool()` from `@opencode-ai/plugin`
80+
2. Import and add to `tool:` object in `src/index.ts`
81+
3. Document in README Tools section
82+
83+
### Adding a New Hook
84+
85+
1. Add implementation in `src/index.ts` return object
86+
2. Follow existing patterns for hook signatures
87+
3. Document behavior in README if user-facing
88+
89+
## Release Process
90+
91+
1. Update version in `package.json`
92+
2. Update `CHANGELOG.md`
93+
3. Commit: `git commit -m "chore: release vX.Y.Z"`
94+
4. Tag: `git tag vX.Y.Z`
95+
5. Push: `git push && git push --tags`
96+
6. GitHub Actions handles npm publish
97+
98+
## Common Patterns
99+
100+
### Config Loading
101+
102+
```typescript
103+
const configResult = loadConfigWithPrecedence(directory)
104+
if (configResult.config === null) {
105+
// No config - return minimal hooks or no-op
106+
return {}
107+
}
108+
```
109+
110+
### Type Guards for Output
111+
112+
```typescript
113+
const output = cmdOutput as { parts: Array<{ type: string; text: string }> }
114+
output.parts.push({ type: "text", text: "Message" })
115+
```
116+
117+
### Mood State Normalization
118+
119+
Always normalize state after loading to handle config changes:
120+
121+
```typescript
122+
const normalized = normalizeState(state, defaultMood, moods)
123+
```
124+
125+
## Constraints
126+
127+
- **Backward Compatible**: Accept old config formats, warn on deprecation
128+
- **No-op Safe**: Return empty hooks if config is missing
129+
- **Deterministic**: Use `mood.seed` for reproducible tests
130+
- **Minimal Dependencies**: Only `@opencode-ai/plugin` peer dependency

CHANGELOG.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [1.0.0] - 2025-02-02
9+
10+
### Added
11+
12+
- Initial release
13+
- Personality injection via `experimental.chat.system.transform` hook
14+
- Mood state machine with configurable drift logic
15+
- `/mood` command for status check and manual mood override
16+
- `/personality` command suite:
17+
- `create` - Interactive personality creation through conversation
18+
- `edit` - Modify existing config (interactive or via `--field`/`--value` flags)
19+
- `show` - Display merged configuration
20+
- `reset` - Delete config file with `--confirm` flag
21+
- `setMood` tool for programmatic mood control with duration options
22+
- `savePersonality` tool for saving configurations via LLM
23+
- Toast notifications on mood drift
24+
- Session compaction support via `experimental.session.compacting`
25+
- Config precedence: global (`~/.config/opencode/`) + project (`.opencode/`) with deep merge
26+
- No-op mode when no config is present
27+
- Custom mood definitions support
28+
- Personality name support
29+
30+
### Technical
31+
32+
- TypeScript strict mode with `noUncheckedIndexedAccess`
33+
- ESM module format
34+
- Bun build pipeline with source maps
35+
- GitHub Actions CI/CD for PR checks and npm publishing

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Joost van Wollingen
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

0 commit comments

Comments
 (0)