@modootoday/pmcp 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -70,6 +70,49 @@ Paths resolve against the file's directory. Keys are `roots`, `scopes`,
70
70
  the same meaning; an unknown key is an error. A flag replaces the file's list
71
71
  of its kind. `--config <file>` names another file and `--no-config` ignores it.
72
72
 
73
+ ## Native files for each agent tool
74
+
75
+ `pmcp project` writes what Claude Code, Codex, Gemini CLI, Grok Build and
76
+ Antigravity read natively, from cross-tool sources under `.agents/`
77
+ (`skills/<name>/SKILL.md`, `agents/<name>/agent.md`, `rules/*.md`) and the rest
78
+ of `pmcp.toml`:
79
+
80
+ ```toml
81
+ [targets]
82
+ tools = ["claude", "codex", "gemini", "grok", "antigravity"]
83
+
84
+ [skills.deploy]
85
+ invocation = "user" # the person starts it; the model is not offered it
86
+
87
+ [agents.reviewer.claude]
88
+ tools = "Read, Grep" # fields one tool reads stay out of agent.md
89
+
90
+ [rules.packages]
91
+ file = ".agent/rules/PACKAGE.RULE.md" # each package's path-scoped rule
92
+ strip = ["apps"] # dropped from derived link names
93
+
94
+ [mcp.skills]
95
+ command = "node"
96
+ args = ["${PROJECT_ROOT}/node_modules/@modootoday/pmcp/dist/cli.js", "serve"]
97
+ ```
98
+
99
+ ```sh
100
+ pmcp project # write
101
+ pmcp project --check # exit 2 on drift, stale or undeclared outputs
102
+ pmcp project add <name> # copy a catalog skill or agent into .agents/
103
+ pmcp project remove <name>
104
+ pmcp doctor # ask each installed tool what it loads
105
+ ```
106
+
107
+ Rules go to `.claude/rules/<dir>/`, never the top level, because Grok Build
108
+ loads top-level `.claude/rules/*.md` in every session regardless of `paths:`.
109
+ A server that names `${PROJECT_ROOT}` is launched through `sh`, which finds
110
+ `pmcp.toml` at spawn time, so the generated files hold no machine's path.
111
+ `pmcp.lock` records what was written; a file pmcp did not write is never
112
+ overwritten. `doctor` calls no model: it reads `claude mcp list`,
113
+ `codex mcp list`, `gemini skills list`, `gemini mcp list` and
114
+ `grok inspect --json`, and skips a tool that is not installed.
115
+
73
116
  ## Package skills
74
117
 
75
118
  Skills are discovered by filename, including `skills/`, `.agents/skills/`,
@@ -1009,6 +1009,10 @@ var readOnly = {
1009
1009
  idempotentHint: true,
1010
1010
  openWorldHint: false
1011
1011
  };
1012
+ var readOnlyTool = (title) => ({
1013
+ title,
1014
+ annotations: { ...readOnly, title }
1015
+ });
1012
1016
  var kindInput = z2.enum(["skill", "agent", "hook", "mcp", "any"]).optional().describe(
1013
1017
  "skill (default), agent, hook, mcp, or any. Commands are skills; agents, hooks and MCP servers are installed with pmcp add rather than read."
1014
1018
  );
@@ -1019,22 +1023,21 @@ function registerSkillTools(server, tools) {
1019
1023
  server.registerTool(
1020
1024
  "skill_catalog",
1021
1025
  {
1022
- title: "List installed skills without their bodies",
1026
+ ...readOnlyTool("List skills"),
1023
1027
  description: "Every skill the installed packages and marketplaces ship, grouped by package or plugin, with names, one-line descriptions and tier, and no bodies. Paged by group. Use it to see what exists, or when skill_find returns nothing. Pass kind to list agents, hooks or MCP servers instead.",
1024
1028
  inputSchema: z2.object({
1025
1029
  page: z2.number().int().min(1).optional(),
1026
1030
  pageSize: z2.number().int().min(1).max(20).optional(),
1027
1031
  tier: z2.enum(["open", "free", "paid", "internal"]).optional(),
1028
1032
  kind: kindInput
1029
- }),
1030
- annotations: readOnly
1033
+ })
1031
1034
  },
1032
1035
  async (request) => asText(tools.catalog(request))
1033
1036
  );
1034
1037
  server.registerTool(
1035
1038
  "skill_find",
1036
1039
  {
1037
- title: "Find skills by describing the problem",
1040
+ ...readOnlyTool("Find skills"),
1038
1041
  description: "Ranked skill names for an intent. Describe the problem in a full sentence in English rather than a keyword: a single word matches far worse, and the ranking is over descriptions. Returns names only -- read one with skill_call.",
1039
1042
  inputSchema: z2.object({
1040
1043
  intent: z2.string().min(1).max(256).describe("What you are trying to do, as an English sentence."),
@@ -1047,20 +1050,18 @@ function registerSkillTools(server, tools) {
1047
1050
  domain: z2.string().optional(),
1048
1051
  medium: z2.string().optional()
1049
1052
  }).optional().describe("Exact-match filters over the catalog before ranking.")
1050
- }),
1051
- annotations: readOnly
1053
+ })
1052
1054
  },
1053
1055
  async ({ intent, limit, filters }) => asText(await tools.find(intent, limit, filters))
1054
1056
  );
1055
1057
  server.registerTool(
1056
1058
  "skill_describe",
1057
1059
  {
1058
- title: "Check one skill's properties before loading it",
1060
+ ...readOnlyTool("Describe a skill"),
1059
1061
  description: "Frontmatter, metadata (tier, level, requirements, licence, approval), and the files the skill carries with sizes and sha256, without any body. Use it to decide between candidates before skill_call.",
1060
1062
  inputSchema: z2.object({
1061
1063
  name: z2.string().min(1).describe("The skill name skill_find or skill_catalog returned.")
1062
- }),
1063
- annotations: readOnly
1064
+ })
1064
1065
  },
1065
1066
  async ({ name }) => {
1066
1067
  const described = tools.describe(name);
@@ -1080,15 +1081,14 @@ function registerSkillTools(server, tools) {
1080
1081
  server.registerTool(
1081
1082
  "skill_read",
1082
1083
  {
1083
- title: "Read one file a skill carries",
1084
- description: "A reference or script file inside one skill's directory, as text, with its sha256. Read only when the skill body points at the file. Scripts are returned, never run. Files over 256 KiB and paths outside the skill are refused.",
1084
+ ...readOnlyTool("Read a skill file"),
1085
+ description: "A reference or script file inside one skill's directory in this catalog, as text, with its sha256. It reads only files the catalog ships and calls no external API; path is relative to the skill, as skill_describe lists it (layout: https://pmcp.build). Read only when the skill body points at the file. Scripts are returned, never run. Files over 256 KiB and paths outside the skill are refused.",
1085
1086
  inputSchema: z2.object({
1086
1087
  name: z2.string().min(1),
1087
1088
  path: z2.string().min(1).optional().describe(
1088
1089
  "Path relative to the skill directory, as skill_describe lists it. Defaults to SKILL.md."
1089
1090
  )
1090
- }),
1091
- annotations: readOnly
1091
+ })
1092
1092
  },
1093
1093
  async ({ name, path }) => {
1094
1094
  const result = tools.read(name, path);
@@ -1105,12 +1105,11 @@ function registerSkillTools(server, tools) {
1105
1105
  server.registerTool(
1106
1106
  "skill_call",
1107
1107
  {
1108
- title: "Read one skill",
1108
+ ...readOnlyTool("Read a skill"),
1109
1109
  description: "The body of a single skill, by the name skill_find or skill_catalog returned. This is the only call that costs a document.",
1110
1110
  inputSchema: z2.object({
1111
1111
  name: z2.string().min(1).describe("The skill name, as <package>/<slug>.")
1112
- }),
1113
- annotations: readOnly
1112
+ })
1114
1113
  },
1115
1114
  async ({ name }) => {
1116
1115
  const found = tools.call(name);
@@ -1130,7 +1129,7 @@ function registerSkillTools(server, tools) {
1130
1129
  return server;
1131
1130
  }
1132
1131
  function createSkillServer(options) {
1133
- const server = new McpServer({ name: SERVER_NAME, version: "0.5.0" });
1132
+ const server = new McpServer({ name: SERVER_NAME, version: "0.6.0" });
1134
1133
  const tools = createSkillTools(options);
1135
1134
  registerSkillsExtension(server, tools.skills);
1136
1135
  return registerSkillTools(server, tools);
@@ -1168,4 +1167,4 @@ export {
1168
1167
  registerSkillTools,
1169
1168
  createSkillServer
1170
1169
  };
1171
- //# sourceMappingURL=chunk-JOQTOVTJ.js.map
1170
+ //# sourceMappingURL=chunk-5TX2IAVD.js.map