Skip to content

Commit 02bbfd5

Browse files
committed
update adding claude.md
1 parent b4f68cb commit 02bbfd5

File tree

11 files changed

+1254
-47
lines changed

11 files changed

+1254
-47
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/bin/sh
2+
if grep -q "caliber" .git/hooks/pre-commit 2>/dev/null; then
3+
exit 0
4+
fi
5+
FLAG="/tmp/caliber-nudge-$(echo "$PWD" | shasum | cut -c1-8)"
6+
find /tmp -maxdepth 1 -name "caliber-nudge-*" -mmin +120 -delete 2>/dev/null
7+
if [ -f "$FLAG" ]; then
8+
exit 0
9+
fi
10+
touch "$FLAG"
11+
printf '{"decision":"block","reason":"Caliber agent config sync is not set up on this machine. Tell the user: This project uses Caliber to keep agent configs in sync — it is not set up yet. Want me to run /setup-caliber? (~30 seconds)"}'

.claude/settings.json

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
{
2+
"hooks": {
3+
"Stop": [
4+
{
5+
"matcher": "",
6+
"hooks": [
7+
{
8+
"type": "command",
9+
"command": ".claude/hooks/caliber-check-sync.sh",
10+
"description": "Caliber: offer setup if not configured"
11+
}
12+
]
13+
}
14+
],
15+
"PostToolUse": [
16+
{
17+
"matcher": "",
18+
"hooks": [
19+
{
20+
"type": "command",
21+
"command": "caliber learn observe",
22+
"description": "Caliber: recording tool usage for session learning"
23+
}
24+
]
25+
}
26+
],
27+
"PostToolUseFailure": [
28+
{
29+
"matcher": "",
30+
"hooks": [
31+
{
32+
"type": "command",
33+
"command": "caliber learn observe --failure",
34+
"description": "Caliber: recording tool failure for session learning"
35+
}
36+
]
37+
}
38+
],
39+
"UserPromptSubmit": [
40+
{
41+
"matcher": "",
42+
"hooks": [
43+
{
44+
"type": "command",
45+
"command": "caliber learn observe --prompt",
46+
"description": "Caliber: recording user prompt for correction detection"
47+
}
48+
]
49+
}
50+
],
51+
"SessionEnd": [
52+
{
53+
"matcher": "",
54+
"hooks": [
55+
{
56+
"type": "command",
57+
"command": "caliber learn finalize --auto",
58+
"description": "Caliber: finalizing session learnings"
59+
}
60+
]
61+
},
62+
{
63+
"matcher": "",
64+
"hooks": [
65+
{
66+
"type": "command",
67+
"command": "caliber refresh --quiet",
68+
"description": "Caliber: auto-refreshing docs based on code changes"
69+
}
70+
]
71+
}
72+
]
73+
},
74+
"permissions": {
75+
"allow": [
76+
"Bash(git *)"
77+
]
78+
}
79+
}
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
---
2+
name: composer-command
3+
description: Creates a new Composer command extending BaseCommand in src/Command/, registers it in CommandProvider.php, and scaffolds a matching PHPUnit test. Use when user says 'add command', 'new composer command', 'create myadmin command'. Do NOT use for modifying existing commands or non-command classes.
4+
---
5+
# Composer Command
6+
7+
Create new Composer CLI commands for the MyAdmin plugin installer, following the existing `BaseCommand` pattern in `src/Command/`.
8+
9+
## Critical
10+
11+
- Command name MUST follow the `myadmin:<kebab-case-name>` convention (e.g., `myadmin:rebuild-cache`). The only exception is the base `myadmin` command in `Command.php`.
12+
- Every new command class MUST be registered in `src/CommandProvider.php` — both as a `use` import and as a `new ClassName()` entry in the `getCommands()` array.
13+
- The `CommandProviderTest.php` test that asserts the command count MUST be updated to match the new total.
14+
- All command classes use `protected function execute(...)` returning `int` (0 for success).
15+
- Namespace is always `MyAdmin\Plugins\Command`.
16+
17+
## Instructions
18+
19+
1. **Choose the command name and class name.**
20+
- Command name: `myadmin:<kebab-case-verb-noun>` (e.g., `myadmin:clear-cache`)
21+
- Class name: PascalCase matching the command (e.g., `ClearCache`)
22+
- Verify the name doesn't conflict with existing commands: `Command`, `Parse`, `CreateUser`, `UpdatePlugins`, `SetPermissions`.
23+
24+
2. **Create the command class at `src/Command/<ClassName>.php`.**
25+
Use this exact template:
26+
27+
```php
28+
<?php
29+
/**
30+
* Plugins Management
31+
* @author Joe Huss <detain@interserver.net>
32+
* @copyright 2025
33+
* @package MyAdmin
34+
* @category Plugins
35+
*/
36+
37+
namespace MyAdmin\Plugins\Command;
38+
39+
use Symfony\Component\Console\Input\InputInterface;
40+
use Symfony\Component\Console\Output\OutputInterface;
41+
use Composer\Command\BaseCommand;
42+
43+
/**
44+
* Class <ClassName>
45+
*
46+
* @package MyAdmin\Plugins\Command
47+
*/
48+
class <ClassName> extends BaseCommand
49+
{
50+
protected function configure()
51+
{
52+
$this
53+
->setName('myadmin:<kebab-name>')
54+
->setDescription('<Short description of what the command does>')
55+
->setHelp('<Longer help text explaining usage>');
56+
}
57+
58+
protected function execute(InputInterface $input, OutputInterface $output): int
59+
{
60+
// Command logic here
61+
62+
return 0;
63+
}
64+
}
65+
```
66+
67+
- If the command needs arguments, add `use Symfony\Component\Console\Input\InputArgument;` and chain `->addArgument('name', InputArgument::REQUIRED, 'Description.')` in `configure()`.
68+
- If the command needs options, add `use Symfony\Component\Console\Input\InputOption;` and chain `->addOption(...)` in `configure()`.
69+
- Only include `initialize()` and `interact()` methods if the command actually needs them. The minimal pattern (see `SetPermissions.php`) omits them.
70+
- Verify the file exists and has correct namespace before proceeding.
71+
72+
3. **Register the command in `src/CommandProvider.php`.**
73+
- Add a `use` import: `use MyAdmin\Plugins\Command\<ClassName>;`
74+
- Add `new <ClassName>()` to the end of the array in `getCommands()`.
75+
- Verify the import is alphabetically consistent with existing imports and the array entry is added.
76+
77+
4. **Create the test file at `tests/Command/<ClassName>Test.php`.**
78+
Follow this template matching the project's ReflectionClass-based testing pattern:
79+
80+
```php
81+
<?php
82+
83+
namespace Tests\MyAdmin\Plugins\Command;
84+
85+
use MyAdmin\Plugins\Command\<ClassName>;
86+
use PHPUnit\Framework\TestCase;
87+
use ReflectionClass;
88+
89+
/**
90+
* Test suite for the <ClassName> command class.
91+
*
92+
* Tests class structure and command configuration.
93+
*
94+
* @covers \MyAdmin\Plugins\Command\<ClassName>
95+
*/
96+
class <ClassName>Test extends TestCase
97+
{
98+
public function testExtendsBaseCommand(): void
99+
{
100+
$ref = new ReflectionClass(<ClassName>::class);
101+
$this->assertSame('Composer\Command\BaseCommand', $ref->getParentClass()->getName());
102+
}
103+
104+
public function testCommandNameIsMyadmin<PascalName>(): void
105+
{
106+
$command = new <ClassName>();
107+
$this->assertSame('myadmin:<kebab-name>', $command->getName());
108+
}
109+
110+
public function testCommandHasDescription(): void
111+
{
112+
$command = new <ClassName>();
113+
$this->assertNotEmpty($command->getDescription());
114+
}
115+
116+
public function testCommandHasHelp(): void
117+
{
118+
$command = new <ClassName>();
119+
$this->assertNotEmpty($command->getHelp());
120+
}
121+
122+
public function testExecuteIsProtected(): void
123+
{
124+
$ref = new ReflectionClass(<ClassName>::class);
125+
$method = $ref->getMethod('execute');
126+
$this->assertTrue($method->isProtected());
127+
}
128+
}
129+
```
130+
131+
- If the command has arguments, add tests for each argument (see `CreateUserTest.php` for the pattern: `testCommandHas<Arg>Argument`, `test<Arg>ArgumentIsRequired`, `test<Arg>ArgumentHasDescription`).
132+
- Verify the test file exists before proceeding.
133+
134+
5. **Update `tests/CommandProviderTest.php`.**
135+
- Update the `testGetCommandsReturns*Commands` test: change the `assertCount` value from the current count to current + 1.
136+
- Add a new test method for the new command instance:
137+
```php
138+
public function testContains<ClassName>Instance(): void
139+
{
140+
$provider = new CommandProvider();
141+
$commands = $provider->getCommands();
142+
$this->assertInstanceOf(\MyAdmin\Plugins\Command\<ClassName>::class, $commands[<new_index>]);
143+
}
144+
```
145+
- The index is the position in the `getCommands()` array (0-based). Currently indices 0-4 are used, so the next is 5.
146+
- Verify the count assertion matches the actual number of commands.
147+
148+
6. **Run tests to verify everything passes.**
149+
```bash
150+
vendor/bin/phpunit tests/Command/<ClassName>Test.php
151+
vendor/bin/phpunit tests/CommandProviderTest.php
152+
```
153+
- All tests must pass. If `CommandProviderTest` fails on count, check that you updated both the array in `CommandProvider.php` and the count assertion in the test.
154+
155+
## Examples
156+
157+
**User says:** "Add a new composer command called rebuild-cache that clears and rebuilds the plugin cache"
158+
159+
**Actions taken:**
160+
1. Create `src/Command/RebuildCache.php` with class `RebuildCache extends BaseCommand`, command name `myadmin:rebuild-cache`.
161+
2. Add `use MyAdmin\Plugins\Command\RebuildCache;` and `new RebuildCache()` to `src/CommandProvider.php`.
162+
3. Create `tests/Command/RebuildCacheTest.php` with tests for: extends BaseCommand, command name, description, help, execute visibility.
163+
4. Update `tests/CommandProviderTest.php`: change `assertCount(5, ...)` to `assertCount(6, ...)`, add `testContainsRebuildCacheInstance` checking `$commands[5]`.
164+
5. Run `vendor/bin/phpunit tests/Command/RebuildCacheTest.php && vendor/bin/phpunit tests/CommandProviderTest.php` — all green.
165+
166+
**Result:** New `myadmin:rebuild-cache` command available via `composer myadmin:rebuild-cache`, fully tested.
167+
168+
## Common Issues
169+
170+
- **`CommandProviderTest::testGetCommandsReturnsFiveCommands` fails with "Failed asserting that 6 matches expected 5"**: You added the command to `CommandProvider.php` but forgot to update the count assertion in `tests/CommandProviderTest.php`. Change `assertCount(5, ...)` to `assertCount(6, ...)`.
171+
172+
- **`Error: Class 'MyAdmin\Plugins\Command\NewCommand' not found`**: The class file exists but the namespace or class name doesn't match. Verify the file has `namespace MyAdmin\Plugins\Command;` and the class name matches the filename exactly (PascalCase).
173+
174+
- **`The command "myadmin:foo" does not exist`**: The command was not registered in `src/CommandProvider.php`. Add both the `use` import and the `new ClassName()` entry in `getCommands()`.
175+
176+
- **`Symfony\Component\Console\Exception\LogicException: The command name "" must not be empty`**: The `configure()` method is missing `->setName('myadmin:<name>')`. Ensure the `configure` method chains `setName()` first.
177+
178+
- **Test instantiation fails with constructor errors**: Do NOT pass constructor arguments to command classes in tests. All existing commands are instantiated with `new ClassName()` (no arguments). The `BaseCommand` constructor is parameterless.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
---
2+
name: find-skills
3+
description: Discovers and installs community skills from the public registry. Use when the user mentions a technology, framework, or task that could benefit from specialized skills not yet installed, asks 'how do I do X', 'find a skill for X', or starts work in a new technology area. Proactively suggest when the user's task involves tools or frameworks without existing skills.
4+
---
5+
6+
# Find Skills
7+
8+
Search the public skill registry for community-contributed skills
9+
relevant to the user's current task and install them into this project.
10+
11+
## Instructions
12+
13+
1. Identify the key technologies, frameworks, or task types from the
14+
user's request that might have community skills available
15+
2. Ask the user: "Would you like me to search for community skills
16+
for [identified technologies]?"
17+
3. If the user agrees, run:
18+
```bash
19+
caliber skills --query "<relevant terms>"
20+
```
21+
This outputs the top 5 matching skills with scores and descriptions.
22+
4. Present the results to the user and ask which ones to install
23+
5. Install the selected skills:
24+
```bash
25+
caliber skills --install <slug1>,<slug2>
26+
```
27+
6. Read the installed SKILL.md files to load them into your current
28+
context so you can use them immediately in this session
29+
7. Summarize what was installed and continue with the user's task
30+
31+
## Examples
32+
33+
User: "let's build a web app using React"
34+
-> "I notice you want to work with React. Would you like me to search
35+
for community skills that could help with React development?"
36+
-> If yes: run `caliber skills --query "react frontend"`
37+
-> Show the user the results, ask which to install
38+
-> Run `caliber skills --install <selected-slugs>`
39+
-> Read the installed files and continue
40+
41+
User: "help me set up Docker for this project"
42+
-> "Would you like me to search for Docker-related skills?"
43+
-> If yes: run `caliber skills --query "docker deployment"`
44+
45+
User: "I need to write tests for this Python ML pipeline"
46+
-> "Would you like me to find skills for Python ML testing?"
47+
-> If yes: run `caliber skills --query "python machine-learning testing"`
48+
49+
## When NOT to trigger
50+
51+
- The user is working within an already well-configured area
52+
- You already suggested skills for this technology in this session
53+
- The user is in the middle of urgent debugging or time-sensitive work
54+
- The technology is too generic (e.g. just "code" or "programming")

0 commit comments

Comments
 (0)