modify template

This commit is contained in:
김경종
2026-06-10 17:12:23 +09:00
parent 2d59191df2
commit df3cc3e890
186 changed files with 24935 additions and 2 deletions
@@ -0,0 +1,143 @@
# Updating Existing Local Plugins
Use this reference when a plugin already exists and the request is about updating the plugin during
local development.
All scripts here are specified relative to the skill root. Update the path for running the scripts
depending on your current working directory.
## When To Use This Flow
Use this flow when all of the following are true:
- the plugin already exists locally
- the marketplace entry already points at the plugin source you are editing
- the user wants Codex to see the updated plugin without manually editing marketplace files
If the user still needs the initial plugin entry or marketplace structure created, use the scaffold
flow first and only then switch to this reinstall flow.
## Update Loop
1. Update the plugin manifest to a single Codex cachebuster suffix:
```bash
python3 scripts/update_plugin_cachebuster.py \
<plugin-path>
```
Prefer the default helper behavior here. If you omit `--cachebuster`, the helper uses a UTC
timestamp down to seconds, which is the recommended path for routine local iteration.
Only use a manual cachebuster override when the user explicitly asks for one or when a workflow
outside Codex depends on a specific token:
```bash
python3 scripts/update_plugin_cachebuster.py \
<plugin-path> \
--cachebuster local-20260519-184516
```
2. For the default scaffolded flow, read the marketplace name from the personal marketplace file:
```bash
python3 scripts/read_marketplace_name.py
```
Here, "personal marketplace" means the marketplace whose file is at
`~/.agents/plugins/marketplace.json`. On Windows, use the equivalent path under the user profile.
The helper uses Python's home-directory resolution and prints the marketplace name to use when
constructing the install command.
To read the name from a different marketplace file, pass the path directly:
```bash
python3 scripts/read_marketplace_name.py --marketplace-path <path-to-marketplace.json>
```
3. Reinstall from that marketplace name:
```bash
codex plugin add <plugin-name>@<marketplace-name-from-marketplace-json>
```
The default personal marketplace is discovered implicitly from
`~/.agents/plugins/marketplace.json`. You do not need `codex plugin marketplace add` for that
path, and `codex plugin marketplace list` is not the right check for whether that default
marketplace exists.
4. If the plugin is not using the personal marketplace file, check which configured local
marketplace is actually surfacing that plugin:
```bash
codex plugin list
```
If the plugin is not in the personal marketplace file, confirm which marketplace entry points at
the plugin source you are editing and make sure that marketplace is still local. If it is a
different local marketplace, reinstall from that marketplace name instead of forcing the personal
marketplace flow. If it is not local, stop and help the user resolve the mismatch before
continuing.
5. If the plugin lives in a different confirmed local marketplace, substitute that marketplace
name:
```bash
codex plugin add <plugin-name>@<local-marketplace>
```
6. Prompt the user to use a new thread to try the updated plugin, so that Codex picks up new skills
and tools.
## Cachebuster Policy
- Preserve the existing version prefix and replace only the suffix.
- Treat the preserved prefix as everything before `+`.
- Use the format:
```text
<base-version>+codex.<cachebuster>
```
Examples:
- `0.1.0``0.1.0+codex.local-20260519-184516`
- `0.1.0+codex.old-token``0.1.0+codex.local-20260519-184516`
- `1.2.3-beta.1+codex.prev``1.2.3-beta.1+codex.local-20260519-184516`
- `dev-build+other-tag``dev-build+codex.local-20260519-184516`
Replace the existing Codex cachebuster instead of appending another one. Do not keep incrementing
numeric version components just to trigger reinstall behavior.
## Marketplace Rules
- Marketplace manipulation should happen through commands, not by hand-editing `marketplace.json`
or `config.toml` during this update/reinstall flow.
- Prefer the personal marketplace file for the default scaffolded flow.
- Read the personal marketplace name with
`python3 scripts/read_marketplace_name.py` and use the printed value when constructing
`codex plugin add <plugin-name>@<marketplace-name>`.
- For non-default marketplace files, use
`python3 scripts/read_marketplace_name.py --marketplace-path <path-to-marketplace.json>` to read
the name before constructing reinstall commands.
- Do not tell the user to run `codex plugin marketplace add` for the default personal-marketplace
flow. That marketplace is discovered implicitly by Codex.
- If the user specified a different marketplace path, make sure that marketplace is installed
before giving install or reinstall instructions. Non-default marketplace paths are not
discovered implicitly.
- Use `codex plugin list` when the plugin lives in a different configured marketplace and you need
to confirm which marketplace is surfacing that plugin.
- If a non-default local marketplace has not been configured yet, install it with
`codex plugin marketplace add <path-to-marketplace-root>` before telling the user to run
`codex plugin add <plugin-name>@<marketplace-name>`.
- If the plugin is not in the personal marketplace file, confirm that the selected marketplace is
local before telling the user to reinstall from it.
- If the selected marketplace is not local, stop and help the user resolve that mismatch rather
than pretending the normal local reinstall flow applies.
- If the plugin source is not already the source referenced by the chosen marketplace entry, stop
and fix that first. This update flow does not rewrite marketplace entries.
## After Reinstall
After reinstalling, prompt the user to start a new thread for testing. That is the safe boundary for
picking up the updated plugin and its MCP tools.
@@ -0,0 +1,194 @@
# Plugin JSON sample spec
```json
{
"name": "plugin-name",
"version": "1.2.0",
"description": "Brief plugin description",
"author": {
"name": "Author Name",
"email": "author@example.com",
"url": "https://github.com/author"
},
"homepage": "https://docs.example.com/plugin",
"repository": "https://github.com/author/plugin",
"license": "MIT",
"keywords": ["keyword1", "keyword2"],
"skills": "./skills/",
"hooks": "./hooks.json",
"mcpServers": "./.mcp.json",
"apps": "./.app.json",
"interface": {
"displayName": "Plugin Display Name",
"shortDescription": "Short description for subtitle",
"longDescription": "Long description for details page",
"developerName": "OpenAI",
"category": "Productivity",
"capabilities": ["Interactive", "Write"],
"websiteURL": "https://openai.com/",
"privacyPolicyURL": "https://openai.com/policies/row-privacy-policy/",
"termsOfServiceURL": "https://openai.com/policies/row-terms-of-use/",
"defaultPrompt": [
"Summarize my inbox and draft replies for me.",
"Find open bugs and turn them into Linear tickets.",
"Review today's meetings and flag scheduling gaps."
],
"brandColor": "#3B82F6",
"composerIcon": "./assets/icon.png",
"logo": "./assets/logo.png",
"screenshots": [
"./assets/screenshot1.png",
"./assets/screenshot2.png",
"./assets/screenshot3.png"
]
}
}
```
## Field guide
### Top-level fields
- `name` (`string`): Plugin identifier (kebab-case, no spaces). Required if `plugin.json` is provided and used as manifest name and component namespace.
- `version` (`string`): Plugin semantic version.
- `description` (`string`): Short purpose summary.
- `author` (`object`): Publisher identity.
- `name` (`string`): Author or team name.
- `email` (`string`): Contact email.
- `url` (`string`): Author/team homepage or profile URL.
- `homepage` (`string`): Documentation URL for plugin usage.
- `repository` (`string`): Source code URL.
- `license` (`string`): License identifier (for example `MIT`, `Apache-2.0`).
- `keywords` (`array` of `string`): Search/discovery tags.
- `skills` (`string`): Relative path to skill directories/files.
- `hooks` (`string`): Hook config path.
- `mcpServers` (`string`): MCP config path.
- `apps` (`string`): App manifest path for plugin integrations.
- `interface` (`object`): Interface/UX metadata block for plugin presentation.
### `interface` fields
- `displayName` (`string`): User-facing title shown for the plugin.
- `shortDescription` (`string`): Brief subtitle used in compact views.
- `longDescription` (`string`): Longer description used on details screens.
- `developerName` (`string`): Human-readable publisher name.
- `category` (`string`): Plugin category bucket.
- `capabilities` (`array` of `string`): Capability list from implementation.
- `websiteURL` (`string`): Public website for the plugin.
- `privacyPolicyURL` (`string`): Privacy policy URL.
- `termsOfServiceURL` (`string`): Terms of service URL.
- `defaultPrompt` (`array` of `string`): Starter prompts shown in composer/UX context.
- Include at most 3 strings. Entries after the first 3 are ignored and will not be included.
- Each string is capped at 128 characters. Longer entries are truncated.
- Prefer short starter prompts around 50 characters so they scan well in the UI.
- `brandColor` (`string`): Theme color for the plugin card.
- `composerIcon` (`string`): Path to icon asset.
- `logo` (`string`): Path to logo asset.
- `screenshots` (`array` of `string`): List of screenshot asset paths.
- Screenshot entries must be PNG filenames and stored under `./assets/`.
- Keep file paths relative to plugin root.
### Path conventions and defaults
- Path values should be relative and begin with `./`.
- `skills`, `hooks`, and `mcpServers` are supplemented on top of default component discovery; they do not replace defaults.
- Custom path values must follow the plugin root convention and naming/namespacing rules.
- This repos scaffold writes `.codex-plugin/plugin.json`; treat that as the manifest location this skill generates.
# Marketplace JSON sample spec
`marketplace.json` depends on where the plugin should live. New plugin creation defaults to the
personal marketplace unless the caller explicitly requests a repo-local destination:
- Personal plugin: `~/.agents/plugins/marketplace.json`
- Repo/team plugin: `<repo-root>/.agents/plugins/marketplace.json`
```json
{
"name": "openai-curated",
"interface": {
"displayName": "ChatGPT Official"
},
"plugins": [
{
"name": "linear",
"source": {
"source": "local",
"path": "./plugins/linear"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Productivity"
}
]
}
```
## Marketplace field guide
### Top-level fields
- `name` (`string`): Marketplace identifier or catalog name.
- `interface` (`object`, optional): Marketplace presentation metadata.
- `plugins` (`array`): Ordered plugin entries. This order determines how Codex renders plugins.
### `interface` fields
- `displayName` (`string`, optional): User-facing marketplace title.
### Plugin entry fields
- `name` (`string`): Plugin identifier. Match the plugin folder name and `plugin.json` `name`.
- `source` (`object`): Plugin source descriptor.
- `source` (`string`): Use `local` for this repo workflow.
- `path` (`string`): Relative plugin path based on the marketplace root.
- Personal plugin in `~/.agents/plugins/marketplace.json`: `./plugins/<plugin-name>`
- Repo/team plugin: `./plugins/<plugin-name>`
- The same relative path convention is used for both personal and repo/team marketplaces.
- Example: with `~/.agents/plugins/marketplace.json`, `./plugins/<plugin-name>` resolves to
`~/plugins/<plugin-name>`.
- `policy` (`object`): Marketplace policy block. Always include it.
- `installation` (`string`): Availability policy.
- Allowed values: `NOT_AVAILABLE`, `AVAILABLE`, `INSTALLED_BY_DEFAULT`
- Default for new entries: `AVAILABLE`
- `authentication` (`string`): Authentication timing policy.
- Allowed values: `ON_INSTALL`, `ON_USE`
- Default for new entries: `ON_INSTALL`
- `products` (`array` of `string`, optional): Product override for this plugin entry. Omit it unless product gating is explicitly requested.
- `category` (`string`): Display category bucket. Always include it.
### Marketplace generation rules
- `displayName` belongs under the top-level `interface` object, not individual plugin entries.
- When creating a new marketplace file from scratch, seed `interface.displayName` alongside top-level `name`.
- Always include `policy.installation`, `policy.authentication`, and `category` on every generated or updated plugin entry.
- Treat `policy.products` as an override and omit it unless explicitly requested.
- Append new entries unless the user explicitly requests reordering.
- Replace an existing entry for the same plugin only when overwrite is intentional.
- Default new plugin creation to the personal marketplace.
- Use a repo/team marketplace only when the user specifically requests that destination.
- Only override the marketplace `name` when the default `personal` name is already taken or
installed and you need to seed a different new marketplace file.
- Choose marketplace location to match the selected destination:
- Personal plugin: `~/.agents/plugins/marketplace.json`
- Repo/team plugin: `<repo-root>/.agents/plugins/marketplace.json`
### Plugin validation notes
- The validator mirrors the workspace plugin ingestion schema so generated plugins follow the same
manifest contract from the start.
- Plugin manifests must include real values for `name`, `version`, `description`,
`author.name`, and the required `interface` fields.
- `version` must use strict semver.
- `websiteURL`, `privacyPolicyURL`, and `termsOfServiceURL` must be absolute `https://` URLs when
present.
- `composerIcon`, `logo`, and `screenshots` must point to real files inside the plugin archive when
present.
- `apps` and `mcpServers` should appear in `plugin.json` only when `.app.json` and `.mcp.json`
actually exist.
- Validation rejects unsupported manifest fields such as `hooks`, so the scaffold keeps them out of
generated manifests.
- Run `scripts/validate_plugin.py <plugin-path>` before handing back a generated plugin. It adds one
intentional preflight check that rejects leftover `[TODO: ...]` placeholders.