OpenPackage Documentation

repository·main·Indexed 20 days ago

https://github.com/enulus/openpackage

OpenPackage (opkg v0.11.3) is a package manager for AI coding agent configurations. It provides a unified system to install, manage, and package rules, commands, agents, skills, and MCPs across platforms including Cursor, Claude Code, and GitHub Copilot. The tool features a pipeline architecture for installation, supports multiple source loaders (Registry, Path, Git, Workspace), and allows users to create modular packages with a required openpackage.yml manifest.

Tokens
157.1K
Snippets
462
Records
656
Agent score
69%

What's inside OpenPackage

  1. Overview of the OpenPackage Platform System

    main

    The Platform System is a declarative transformation engine designed to map universal package content to platform-specific formats. It supports over 14 AI coding platforms (such as Cursor, Claude, Windsurf, and Gemini) by using configuration-driven transformations rather than imperative code.

    Key characteristics include:

    • Declarative: Uses JSON configuration for all transformations.
    • Bidirectional: Supports explicit export flows (Package $\rightarrow$ Workspace/Platform) and import flows (Workspace/Platform $\rightarrow$ Package).
    • Composable: Allows merging multi-package content with defined priority levels.
    • Format-agnostic: Handles JSON, YAML, TOML, JSONC, and Markdown.
    • Type-safe: Provides schema validation and IDE autocomplete.
  2. What is the Model Context Protocol (MCP) in Codex?

    main

    The Model Context Protocol (MCP) allows Codex to connect to external tools and context. This enables the model to access third-party documentation or interact with developer tools like browsers or Figma.

    Codex supports two types of MCP servers:

    1. STDIO servers: Local processes started via a command. These support environment variables.
    2. Streamable HTTP servers: Servers accessed via a URL. These support Bearer token authentication and OAuth (via codex mcp login <server-name>).

    Configuration is shared between the Codex CLI and the IDE extension via the ~/.codex/config.toml file.

  3. Organize Universal Content Layout

    main

    Universal subdirectories are canonical at the package root. Standard subdirectories include agents/, rules/, commands/, and skills/, though custom subdirectories can be defined in platforms.jsonc.

    To support platform-specific variations, you can use two types of markdown files:

    • Universal markdown: e.g., agents/foo.md. This is the single source of truth for the shared body and shared frontmatter.
    • Platform-suffixed markdown: e.g., agents/foo.<platform>.md. These are optional files used to provide platform-specific body overrides.
    <package-root>/
      openpackage.yml              # package manifest
      <universal-subdir>/
        <name>.md                  # universal markdown
        <name>.<platform>.md       # platform-suffixed markdown (optional)
  4. Understand the role of openpackage.yml as the source of truth

    main

    In OpenPackage, openpackage.yml serves as the canonical declaration of intent for your project's dependencies. It defines the version ranges and sources that the project tracks.

    Key principles of the canonical model:

    • Direct Dependencies: openpackage.yml is the absolute source of truth. CLI commands cannot silently override the declarations made in this file.
    • CLI Interaction: When you use the CLI, it interacts with the canonical file in two ways:
      • Seeding: For fresh installs (packages not yet in the file), the CLI creates new entries in openpackage.yml.
      • Compatibility Hints: For existing packages, CLI flags act as hints to ensure the requested installation is compatible with the ranges already declared in openpackage.yml.
    • Semantic Changes: If you need to change the major version line a dependency tracks, you must manually edit openpackage.yml. You cannot change the fundamental dependency intent using install flags.
  5. Relationship between `opkg` commands

    main

    Understanding how save fits into the broader OpenPackage ecosystem:

    • opkg install: Forward sync (Source $\rightarrow$ Workspace).
    • opkg save: Reverse sync (Workspace $\rightarrow$ Source).
    • opkg add: Adds new files to the package source without performing a sync. Note that opkg save only syncs files already tracked in the workspace index; use opkg add for entirely new files.
    • opkg pack: Creates a registry snapshot from the current package source.
  6. Use $switch for conditional target paths

    main

    The $switch expression allows you to resolve target paths conditionally based on context variables, preventing the need to duplicate entire flow definitions. It can be used in both from and to fields of a flow.

    Syntax

    {
      "field": "$$variableName",
      "cases": [
        { "pattern": "pattern1", "value": "result1" },
        { "pattern": "pattern2", "value": "result2" }
      ],
      "default": "fallback_value"
    }

    Pattern Matching Types

    • Exact String Match: Matches the string exactly (e.g., "~/").
    • Glob Patterns: Supports minimatch syntax (*, **, ?, [...]).
    • Object Pattern Matching: Performs a deep equality check on objects.

    Evaluation Rules

    • First Match Wins: Cases are evaluated in order. Once a pattern matches, its value is returned and subsequent cases are ignored.
    • Default Handling: If no cases match, the default value is used. If no default is provided and no cases match, the flow fails with an error.

    Available Context Variables

    • $$targetRoot: The installation target root (e.g., "~/", "/project").
    • $$platform: The current platform name (e.g., "cursor", "claude").
    • $$source: The source platform for conversion.
    • Custom Variables: Passed via the --variables CLI flag.
    {
      "from": "commands/**/*.md",
      "to": {
        "$switch": {
          "field": "$$targetRoot",
          "cases": [
            { "pattern": "~/", "value": ".config/opencode/command/**/*.md" }
          ],
          "default": ".opencode/command/**/*.md"
        }
      }
    }
  7. How key tracking works for merged files

    main

    Key tracking is used when packages use flow-based transformations with merge: 'deep' or merge: 'shallow' strategies. This allows OpenPackage to perform precise removals during uninstallation.

    Key Tracking Mechanics:

    • When tracked: Used when a target file is shared by multiple packages via a merge strategy. The index stores specific dot-notation paths (e.g., mcp.server1) that this package owns.
    • When NOT tracked: Used for merge: 'replace', merge: 'composite', or simple file copies. In these cases, the file is treated as being owned entirely by one package (simple string mapping).

    Dot-notation examples:

    • mcp.server1 maps to { "mcp": { "server1": ... } }
    • editor.fontSize maps to { "editor": { "fontSize": ... } }
    # Example of complex mapping with key tracking
    mcp.jsonc:
      - target: .opencode/opencode.json
        merge: deep
        keys:
          - mcp.server1
          - mcp.server2
  8. Understand Marketplace Plugin Naming and Scoping

    main

    Plugins installed via a marketplace use a scoped naming convention to prevent collisions: {plugin-name}@{scope}.

    The scope is determined based on the source type:

    • Relative path sources: The scope is the marketplace name (e.g., code-formatter@company-tools).
    • External GitHub sources: The scope is the repository name (e.g., deployment-tools@deploy-plugin).
    • External Git URL sources: The scope is the repository name (e.g., ci-integration@platform-tools).

    Uniqueness Rules:

    • Within a single workspace, the combination of {name}@{scope} must be unique.
    • You cannot install the same plugin from the same marketplace twice.
    • You can install the same plugin name from different marketplaces (different scopes).
    • You can install different plugins that happen to share the same name (different scopes).
  9. How `opkg install` resolution works (Mental Model)

    main

    The core philosophy of the install command is: "openpackage.yml declares intent, install materializes the newest versions that satisfy that intent."

    Key Principles:

    • Latest in range: The system always seeks the highest semver version that satisfies the range defined in openpackage.yml.
    • Local-first with remote-fallback: For fresh dependencies, the system first attempts to satisfy the range using only the local registry. If the local registry cannot satisfy the range, it falls back to remote versions.
    • Uniformity: This resolution policy applies to the root package, all transitive dependencies, and all dependency validation checks.
  10. Compare OpenPackage scopes (Local, Root, Global, Custom)

    main

    Choosing the right scope depends on your project structure and distribution needs:

    ScopeBest Use CaseWorkspace IntegrationPortability
    LOCALProject-specific packages (Default)✅ Automatic✅ High (Relative)
    ROOTStandalone repos for distribution❌ Manual (Add path)✅ High (Git)
    GLOBALPersonal utilities across projects❌ Manual (Add path)⚠️ Per-user (Tilde)
    CUSTOMMonorepos or existing structures❌ Manual (Add path)⚠️ Varies

    Decision Logic:

    • Need to match existing directory structure? $\rightarrow$ CUSTOM PATH
    • Package for one project only? $\rightarrow$ LOCAL
    • Package shareable? $\rightarrow$ GLOBAL (Personal) or ROOT (Team/Distribution)
  11. Understand the transformed plugin directory structure

    main

    When a Claude Code plugin is installed, the OpenPackage CLI transforms the .claude-plugin/ directory into a .openpackage/ directory. This ensures the content is compatible with the OpenPackage ecosystem while preserving all original functionality.

    Transformed Layout:

    • .openpackage/plugin.json: Transformed from the original .claude-plugin/plugin.json.
    • .openpackage/commands/: Markdown files for commands.
    • .openpackage/agents/: Markdown files for agents.
    • .openpackage/hooks/: hooks.json file.
    • .openpackage/servers/: Contains mcp-servers.json and lsp-servers.json.
    .openpackage/
    ├── plugin.json
    ├── commands/
    │   ├── command1.md
    │   └── command2.md
    ├── agents/
    │   └── agent1.md
    ├── hooks/
    │   └── hooks.json
    └── servers/
        ├── mcp-servers.json
        └── lsp-servers.json