Skip to main content
Glama

cantrip_init

Initialize a new project in Cantrip by creating it with a name and description, optionally using a product brief to automatically extract key business entities like ICPs and pain points, or starting empty to add entities manually.

Instructions

Create a new project and connect this workspace to it. Pass 'brief_text' (product brief as text) to auto-extract ICPs, pain points, and value props as inferred entities (costs 5 credits). Or pass 'brief_path' (absolute file path) and the file will be read locally. Without a brief, the project is created empty (free) and you add entities manually. Writes .cantrip.json automatically after creation. After creating a project, add a few entities and confirm them with the user before going deeper.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
nameYesProject name
descriptionYesOne-line project description
brief_textNoProduct brief content as text (preferred)
brief_pathNoAbsolute path to a product brief file — will be read locally and sent as text

Implementation Reference

  • The handler function for cantrip_init that creates a new project. It generates a slug from the name, optionally reads a brief file, posts to the 'init' API endpoint, and writes the project context to .cantrip.json.
      handler: async (p) => {
        const slug = String(p.name).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
        let briefText = p.brief_text;
        if (!briefText && p.brief_path) {
          const { readFileSync } = await import("fs");
          briefText = readFileSync(String(p.brief_path), "utf-8");
        }
        const flags = buildFlags({
          name: p.name,
          description: p.description,
          brief_text: briefText,
          project: slug,
        });
        const result = await client.post("init", [], flags);
        writeProjectContext(slug);
        return result;
      },
    },
  • Zod schema defining the input parameters for cantrip_init: name (required), description (required), brief_text (optional), and brief_path (optional).
    shape: {
      name: z.string().describe("Project name"),
      description: z.string().describe("One-line project description"),
      brief_text: z
        .string()
        .optional()
        .describe("Product brief content as text (preferred)"),
      brief_path: z
        .string()
        .optional()
        .describe("Absolute path to a product brief file — will be read locally and sent as text"),
    },
  • src/tools.ts:169-208 (registration)
    Tool registration within the createTools function, defining the cantrip_init tool with its name, description, schema, and handler.
    // ── Init ──
    {
      name: "cantrip_init",
      description:
        "Create a new project and connect this workspace to it. " +
        "Pass 'brief_text' (product brief as text) to auto-extract ICPs, pain points, and value props as inferred entities (costs 5 credits). " +
        "Or pass 'brief_path' (absolute file path) and the file will be read locally. " +
        "Without a brief, the project is created empty (free) and you add entities manually. " +
        "Writes .cantrip.json automatically after creation. " +
        "After creating a project, add a few entities and confirm them with the user before going deeper.",
      shape: {
        name: z.string().describe("Project name"),
        description: z.string().describe("One-line project description"),
        brief_text: z
          .string()
          .optional()
          .describe("Product brief content as text (preferred)"),
        brief_path: z
          .string()
          .optional()
          .describe("Absolute path to a product brief file — will be read locally and sent as text"),
      },
      handler: async (p) => {
        const slug = String(p.name).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
        let briefText = p.brief_text;
        if (!briefText && p.brief_path) {
          const { readFileSync } = await import("fs");
          briefText = readFileSync(String(p.brief_path), "utf-8");
        }
        const flags = buildFlags({
          name: p.name,
          description: p.description,
          brief_text: briefText,
          project: slug,
        });
        const result = await client.post("init", [], flags);
        writeProjectContext(slug);
        return result;
      },
    },
  • Helper function that builds a flags object from parameters, filtering out undefined, null, and empty string values.
    function buildFlags(params: Record<string, unknown>): Record<string, string> {
      const flags: Record<string, string> = {};
      for (const [k, v] of Object.entries(params)) {
        if (v !== undefined && v !== null && v !== "") {
          flags[k] = String(v);
        }
      }
      return flags;
    }
  • Helper function that writes the project slug to .cantrip.json file, connecting the workspace to the newly created project.
    export function writeProjectContext(project: string): void {
      writeFileSync(
        getConfigPath(),
        JSON.stringify({ project }, null, 2) + "\n",
        "utf-8",
      );
    }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ozten/mcp-server-cantrip'

If you have feedback or need assistance with the MCP directory API, please join our Discord server