Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions .mise/locks/trunk/1.3.4/aube-lock.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
lockfileVersion: '9.0'

settings:
autoInstallPeers: true
excludeLinksFromLockfile: false

importers:

.:
dependencies:
'@trunkio/launcher':
specifier: 1.3.4
version: 1.3.4

packages:

'@trunkio/launcher@1.3.4':
resolution: {integrity: sha512-4LCsFVvZtKht7EkbOq5gDsRLIBOH05ycNxm1Vrv+YzY+uOK2HueLBcLU8oejV9v01LTtWjfLJxonIgTSo7lwng==}
engines: {node: '>=18.0.0'}
hasBin: true

chownr@2.0.0:
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
engines: {node: '>=10'}

fs-minipass@2.1.0:
resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==}
engines: {node: '>= 8'}

minipass@3.3.6:
resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==}
engines: {node: '>=8'}

minipass@5.0.0:
resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==}
engines: {node: '>=8'}

minizlib@2.1.2:
resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==}
engines: {node: '>= 8'}

mkdirp@1.0.4:
resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
engines: {node: '>=10'}
hasBin: true

semver@7.8.5:
resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==}
engines: {node: '>=10'}
hasBin: true

tar@6.2.1:
resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==}
engines: {node: '>=10'}
deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me

yallist@4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}

yaml@2.9.1:
resolution: {integrity: sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==}
engines: {node: '>= 14.6'}
hasBin: true

snapshots:

'@trunkio/launcher@1.3.4':
dependencies:
semver: 7.8.5
tar: 6.2.1
yaml: 2.9.1

chownr@2.0.0: {}

fs-minipass@2.1.0:
dependencies:
minipass: 3.3.6

minipass@3.3.6:
dependencies:
yallist: 4.0.0

minipass@5.0.0: {}

minizlib@2.1.2:
dependencies:
minipass: 3.3.6
yallist: 4.0.0

mkdirp@1.0.4: {}

semver@7.8.5: {}

tar@6.2.1:
dependencies:
chownr: 2.0.0
fs-minipass: 2.1.0
minipass: 5.0.0
minizlib: 2.1.2
mkdirp: 1.0.4
yallist: 4.0.0

yallist@4.0.0: {}

yaml@2.9.1: {}
7 changes: 7 additions & 0 deletions .mise/locks/trunk/1.3.4/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "mise-npm-install",
"private": true,
"dependencies": {
"@trunkio/launcher": "1.3.4"
}
}
1 change: 1 addition & 0 deletions .trunk/trunk.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ lint:
- linters: [markdownlint, prettier]
paths:
- CHANGELOG.md
- .mise/**/*.yaml
enabled:
- gofmt@1.20.4
- osv-scanner@2.6.0
Expand Down
29 changes: 20 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ binary and copied to agent directories by `thts init agents`.
| -------- | ------------ | -------------------------------- | -------------------- | --------------- | ---------------- |
| Claude | `.claude/` | `skills/*.md` | `commands/` | `hooks/` | `settings.json` |
| Codex | `.codex/` | `skills/*/SKILL.md` | `prompts/` (global) | None | `config.toml` |
| OpenCode | `.opencode/` | `skills/*/SKILL.md` | `commands/` | `plugins/` | `opencode.json` |
| OpenCode | `.opencode/` | `skills/*/SKILL.md` | `commands/` | `plugins/` | Not thts-managed |
| Gemini | `.gemini/` | `skills/*/SKILL.md` | `commands/*.toml` | `hooks/` | `settings.json` |
| Pi | `.pi/` | `skills/thts-integrate/SKILL.md` | `prompts/` | `extensions/` | Not thts-managed |
| Droid | `.factory/` | `skills/*/SKILL.md` | `commands/` | `hooks/` | Not thts-managed |
Expand All @@ -94,14 +94,14 @@ standalone `hooks.json`; do not create or modify its user-owned `settings.json`.

### Hook Support

| Agent | Hook Support | Hook Events | Settings File |
| -------- | --------------- | ------------------------------------ | --------------------- |
| Claude | Yes | `SessionStart`, `UserPromptSubmit` | `settings.local.json` |
| Gemini | Yes | `SessionStart`, `BeforeAgent` | `settings.local.json` |
| OpenCode | Yes (plugin) | `experimental.chat.system.transform` | N/A (plugin) |
| Pi | Yes (extension) | `before_agent_start` | N/A (extension) |
| Droid | Yes | `SessionStart`, `UserPromptSubmit` | `hooks.json` |
| Codex | No | N/A | N/A |
| Agent | Hook Support | Hook Events | Settings File |
| -------- | --------------- | ----------------------------------------------- | --------------------- |
| Claude | Yes | `SessionStart`, `UserPromptSubmit` | `settings.local.json` |
| Gemini | Yes | `SessionStart`, `BeforeAgent` | `settings.local.json` |
| OpenCode | Yes (plugin) | v1 system transform; v2 `context`, `compaction` | N/A (plugin) |
| Pi | Yes (extension) | `before_agent_start` | N/A (extension) |
| Droid | Yes | `SessionStart`, `UserPromptSubmit` | `hooks.json` |
| Codex | No | N/A | N/A |

Pi's project `.pi/` resources require Pi project trust. Non-interactive Pi
runs do not prompt, so use `pi --approve` to load them for one run or
Expand All @@ -111,6 +111,13 @@ Droid snapshots hooks at session startup. Restart it or review/reload through
`/hooks` after changes. `hooksDisabled` or enterprise `allowManagedHooksOnly`
can prevent project or user thts hooks from running.

OpenCode targets v2, retaining best-effort legacy compatibility with v1.18.29+
through its existing API adapter. Its single dependency-free plugin exports
`id`, `server`, and `setup`. V2 policy follows
`session.location.directory`, including shared servers; do not append `subpath`.
Keep settings user-owned. Only an exact, manifest-owned legacy settings template
may be removed during migration. Customized files must survive refresh/uninit.

### Embedded Files

| File | Purpose | Agent Support |
Expand Down Expand Up @@ -183,6 +190,10 @@ go test -tags=integration ./internal/cmd/... # Integration tests
go test -tags=integration ./... # All tests
```

OpenCode adapter behavior is covered by unit tests; installation lifecycle is
covered by `scripts/verify-opencode-integration.sh`. Smoke-test v2 manually when
changing the integration or upgrading across a significant API change.

**Coverage targets:** config/git >70%, fs/thts >60% (all met)

#### Verification Scripts
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ thts sync -m "Added architecture notes"
CLI, Pi, and Droid CLI to give them awareness of your thoughts
directory.

OpenCode integration targets v2, retaining best-effort legacy compatibility with
v1.18.29+. The same plugin handles project and global installs. See the
[OpenCode upgrade instructions](docs/guide.md#upgrading-opencode-integration).

```bash
thts init agents # Install for detected agents
thts init agents -i # Interactive mode
Expand Down
2 changes: 1 addition & 1 deletion docs/contributing-agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ func getPluginsFS(agentType agents.AgentType) fs.FS {
Create a settings template only when thts should manage a default settings file.
The template filename must match `SettingsTemplate`; `SettingsFile` remains the
destination name. Leave `SettingsTemplate` empty when the agent's settings are
user-owned, as for Pi.
user-owned, as for OpenCode, Pi, and Droid.

For testbot with `SettingsFile: "config.json"`:

Expand Down
55 changes: 49 additions & 6 deletions docs/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
- [Global vs Project Configuration](#global-vs-project-configuration)
- [Prerequisites](#prerequisites)
- [Integration Levels](#integration-levels)
- [Upgrading OpenCode Integration](#upgrading-opencode-integration)
- [Pi Project Trust](#pi-project-trust)
- [Customizing Hook Keywords](#customizing-hook-keywords)
- [Claude Plan Directive](#claude-plan-directive)
Expand Down Expand Up @@ -795,6 +796,10 @@ your thoughts directory and enable session continuity.
invoked as `/prompts:<name>` (e.g., `/prompts:thts-handoff`).
- **OpenCode XDG**: OpenCode uses XDG for global config (`~/.config/opencode/`)
rather than a dot-folder in home.
- The plugin targets v2, retaining best-effort legacy compatibility with
v1.18.29+ through its existing API adapter.
- OpenCode settings are user-owned, including
when `--with-settings` is used.
- **Gemini commands**: Gemini stores commands as TOML and does not support
native sub-agents.
- **Pi resources**: Pi uses skills, Markdown prompt templates, and TypeScript
Expand Down Expand Up @@ -892,10 +897,16 @@ Claude and Gemini:
2. Loading full instructions (~200 lines) only when keywords are detected
3. Keywords include: research, plan, decision, thoughts, handoff, notes, etc.

OpenCode uses an idempotent plugin that adds the generated instructions to each
model request without adding another copy when another plugin instance already
supplied it. OpenCode local-only mode installs the same project plugin, which is
covered by the managed thts patterns in `.gitignore`.
OpenCode uses an idempotent plugin that adds generated instructions to normal
agent requests and compaction without adding another copy when policy is already
present in the system instructions. V2 title and transient generation requests
do not receive the policy. On shared servers, the plugin uses the session's
working directory. `thts` must be available on the server's PATH.

OpenCode local-only mode uses the same plugin, covered by the managed thts
patterns in `.gitignore`. With global hooks configured it uses the global plugin.
With hooks disabled, automatic injection is unavailable; enable hooks or select
shared/on-demand integration. OpenCode does not use an `AGENTS.local.md` fallback.

Pi uses an idempotent TypeScript extension at
`.pi/extensions/thts-integration.ts`. It adds the generated policy at
Expand All @@ -920,8 +931,40 @@ integration, or review and reload hooks through `/hooks`. Factory's
`hooksDisabled` setting or an enterprise `allowManagedHooksOnly` policy can
prevent project or user thts hooks from running.

The OpenCode plugin also caches generated instructions for its session. Restart
OpenCode after changing thts categories or instruction configuration.
The OpenCode plugin caches generated instructions per working directory for the
plugin's lifetime, while checking project initialization before each injection.
If a check fails, cached instructions and any pending render for that directory
are discarded.
Restart OpenCode after changing thts categories or instruction configuration.
For v2, restart the server as well as attached clients when a fresh plugin cache
is needed.

#### Upgrading OpenCode Integration

After upgrading thts, refresh existing project resources:

```bash
thts init agents --agents opencode --refresh --dry-run # Preview only
thts init agents --agents opencode --refresh
```

For a global installation, reinstall the global components you use:

```bash
thts init agents --agents opencode --global=all
```

Refresh any existing project installation afterward to remove its owned local
plugin when global hooks are selected. Refresh replaces thts-generated plugin,
skill, command, and subagent files; put custom resources beside them. Restart
OpenCode to load the update. V2 watches plugin files, but a server restart also
clears cached policy.

OpenCode settings are no longer created or owned by thts. Upgrade and uninstall
remove an old manifest-owned `opencode.json` only if it exactly matches the
obsolete thts template. Customized settings are preserved and released from
thts ownership. If they retain the old `permissions.allow` object, follow the
[permissions migration guidance](troubleshooting.md#opencode-settings-errors).

**Note:** Codex does not support hooks and will automatically fall back to
always-on mode with a warning.
Expand Down
33 changes: 33 additions & 0 deletions docs/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,39 @@

## Common Issues

### OpenCode Plugin Not Loading

OpenCode v2 is the actively supported version. Legacy v1.18.29+ compatibility is
best-effort; upgrade to v2 if you encounter a v1-specific issue.
Refresh installed resources after upgrading thts:

```bash
thts init agents --agents opencode --refresh # Project installation
thts init agents --agents opencode --global=all # Global installation
```

Restart OpenCode afterward; for v2 shared servers, restart the server too.
Check `thts init --check` and `thts agent-instructions` from the session's project
directory on the server. The plugin quietly skips injection if either fails or
`thts` is missing from the server's PATH. In v2's active plugin list, its ID is
`thts.integration`.

### OpenCode Settings Errors

Older `thts init agents --with-settings` generated an `opencode.json` containing
`"permissions": { "allow": [] }`. That is not a valid current permissions shape.
If the file is customized, thts preserves it rather than rewriting your settings.

Remove that obsolete empty permissions object, retaining your other settings.
For intentional permission rules, use the schema for your OpenCode version:

- v1 uses `permission`, for example `"permission": { "edit": "ask" }`.
- v2 uses a rule array, for example
`"permissions": [{ "action": "edit", "resource": "*", "effect": "ask" }]`.

See the [v2 permissions guide](https://opencode.ai/v2/docs/permissions). The thts
plugin itself does not require a settings file or a plugin config entry.

### "Run `thts setup` first"

You need to configure thts before using it in any project.
Expand Down
2 changes: 1 addition & 1 deletion embed.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ var Instructions embed.FS
var Templates embed.FS

// Settings contains embedded default settings files for agents.
// Files are named by agent type: codex.toml, opencode.json, etc.
// Files are named by agent type: codex.toml, gemini.json, etc.
// Claude settings are built dynamically and not embedded.
//
//go:embed embedded/settings/*
Expand Down
1 change: 0 additions & 1 deletion embed_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,6 @@ func TestGetDefaultSettingsByTemplateIdentity(t *testing.T) {
}{
{template: "codex.toml", want: "# Codex CLI configuration"},
{template: "gemini.json", want: `"contextFileName": "AGENTS.md"`},
{template: "opencode.json", want: `"model": "anthropic/claude-sonnet-4-20250514"`},
}

for _, tt := range tests {
Expand Down
Loading
Loading