Documentation
¶
Index ¶
- Variables
- func Attach(mux goahttp.Muxer, service *Service)
- func ClaudeObservabilitySlug(cfg GenerateConfig) string
- func CodexObservabilitySlug(cfg GenerateConfig) string
- func CursorObservabilitySlug(cfg GenerateConfig) string
- func GenerateCodexInstallScript(marketplaceURL string, cfg GenerateConfig) ([]byte, error)
- func GenerateObservabilityPluginPackage(cfg GenerateConfig, platform string) (map[string][]byte, error)
- func GeneratePluginPackages(plugins []PluginInfo, cfg GenerateConfig) (map[string][]byte, error)
- func GenerateSinglePluginPackage(plugin PluginInfo, cfg GenerateConfig, platform string) (map[string][]byte, error)
- type GenerateConfig
- type GitHubConfig
- type GitHubConfigInput
- type GitHubPublisher
- type PluginInfo
- type PluginServerInfo
- type ServerEnvConfig
- type Service
- func (s *Service) APIKeyAuth(ctx context.Context, key string, schema *security.APIKeyScheme) (context.Context, error)
- func (s *Service) AddPluginServer(ctx context.Context, payload *gen.AddPluginServerPayload) (*gen.PluginServer, error)
- func (s *Service) CreatePlugin(ctx context.Context, payload *gen.CreatePluginPayload) (*gen.Plugin, error)
- func (s *Service) DeletePlugin(ctx context.Context, payload *gen.DeletePluginPayload) error
- func (s *Service) DownloadCodexInstallScript(ctx context.Context, payload *gen.DownloadCodexInstallScriptPayload) (*gen.DownloadCodexInstallScriptResult, io.ReadCloser, error)
- func (s *Service) DownloadObservabilityPlugin(ctx context.Context, payload *gen.DownloadObservabilityPluginPayload) (*gen.DownloadObservabilityPluginResult, io.ReadCloser, error)
- func (s *Service) DownloadPluginPackage(ctx context.Context, payload *gen.DownloadPluginPackagePayload) (*gen.DownloadPluginPackageResult, io.ReadCloser, error)
- func (s *Service) GetPlugin(ctx context.Context, payload *gen.GetPluginPayload) (*gen.Plugin, error)
- func (s *Service) GetPublishStatus(ctx context.Context, payload *gen.GetPublishStatusPayload) (*gen.PublishStatusResult, error)
- func (s *Service) ListPlugins(ctx context.Context, payload *gen.ListPluginsPayload) (*gen.ListPluginsResult, error)
- func (s *Service) PublishPlugins(ctx context.Context, payload *gen.PublishPluginsPayload) (*gen.PublishPluginsResult, error)
- func (s *Service) RemovePluginServer(ctx context.Context, payload *gen.RemovePluginServerPayload) error
- func (s *Service) SetPluginAssignments(ctx context.Context, payload *gen.SetPluginAssignmentsPayload) (*gen.SetPluginAssignmentsResult, error)
- func (s *Service) UpdatePlugin(ctx context.Context, payload *gen.UpdatePluginPayload) (*gen.Plugin, error)
- func (s *Service) UpdatePluginServer(ctx context.Context, payload *gen.UpdatePluginServerPayload) (*gen.PluginServer, error)
Constants ¶
This section is empty.
Variables ¶
var ClaudeObservabilityHookEvents = []string{
"PreToolUse",
"PostToolUse",
"PostToolUseFailure",
"SessionStart",
"SessionEnd",
"UserPromptSubmit",
"Stop",
"Notification",
}
ClaudeObservabilityHookEvents are the Claude Code hook events the observability plugin registers against. Names match Claude's hooks.json schema. Claude only invokes hook.sh for events listed here, so any event the Claude() handler in server/internal/hooks/claude_hooks.go expects to record must appear in this list — otherwise it is silently dropped on the client side.
var CodexObservabilityHookEvents = []string{
"SessionStart",
"PreToolUse",
"PermissionRequest",
"PostToolUse",
"UserPromptSubmit",
"Stop",
}
CodexObservabilityHookEvents are Codex's hook event names. Codex uses PascalCase names and has a PermissionRequest event that Claude/Cursor lack.
var CursorObservabilityHookEvents = []string{
"beforeSubmitPrompt",
"stop",
"afterAgentResponse",
"afterAgentThought",
"preToolUse",
"postToolUse",
"postToolUseFailure",
"beforeMCPExecution",
"afterMCPExecution",
}
CursorObservabilityHookEvents are Cursor's native hook event names (per server/design/hooks/design.go:58). Cursor uses different event names than Claude, not a lowercased mirror, so the two lists are maintained separately.
Functions ¶
func ClaudeObservabilitySlug ¶
func ClaudeObservabilitySlug(cfg GenerateConfig) string
ClaudeObservabilitySlug / CursorObservabilitySlug derive the observability plugin's directory name and marketplace identifier from the org slug. Namespacing per-org avoids collisions with user plugins that legitimately use slug "observability". Exported because tests need to predict the published path.
func CodexObservabilitySlug ¶
func CodexObservabilitySlug(cfg GenerateConfig) string
func CursorObservabilitySlug ¶
func CursorObservabilitySlug(cfg GenerateConfig) string
func GenerateCodexInstallScript ¶
func GenerateCodexInstallScript(marketplaceURL string, cfg GenerateConfig) ([]byte, error)
GenerateCodexInstallScript produces a bash install script that:
- Registers the Gram marketplace with the Codex CLI
- Patches ~/.codex/config.toml with feature flags and plugin entry
- Pre-approves all hook events so users skip the manual Settings → Hooks step
When marketplaceURL is empty the script uses the directory it was run from as the marketplace source (suitable for the ZIP-bundled install.sh). When marketplaceURL is non-empty the script registers the remote URL instead.
func GenerateObservabilityPluginPackage ¶
func GenerateObservabilityPluginPackage(cfg GenerateConfig, platform string) (map[string][]byte, error)
GenerateObservabilityPluginPackage produces the file map for a single observability plugin for direct ZIP installation (no <org>-observability/ subdir). Minting a fresh hooks key is the caller's responsibility — this just renders files using cfg.HooksAPIKey.
func GeneratePluginPackages ¶
func GeneratePluginPackages(plugins []PluginInfo, cfg GenerateConfig) (map[string][]byte, error)
GeneratePluginPackages produces the complete file map for a plugin distribution repository containing Claude Code, Cursor, and Codex plugins. Used for GitHub push.
func GenerateSinglePluginPackage ¶
func GenerateSinglePluginPackage(plugin PluginInfo, cfg GenerateConfig, platform string) (map[string][]byte, error)
GenerateSinglePluginPackage produces files for a single plugin with files at the root level (no subdirectory prefix). Used for per-plugin ZIP downloads that can be installed directly via `claude --plugin-dir`.
Types ¶
type GenerateConfig ¶
type GenerateConfig struct {
OrgName string
OrgEmail string
// Base server URL (e.g. https://app.getgram.ai).
ServerURL string
// APIKey is the plaintext consumer-scoped Gram API key to inject into
// MCP server configs. If empty, configs will use placeholder variables.
APIKey string
// HooksAPIKey is the plaintext hooks-scoped Gram API key embedded in the
// observability plugin's hook script. If empty, the observability plugin
// is omitted.
HooksAPIKey string
// ProjectSlug is the publishing project's slug. The Cursor hooks endpoint
// requires it via the Gram-Project header (Claude's does not).
ProjectSlug string
// Version is stamped into every plugin.json. Callers should bump this on
// every publish so platform marketplaces (Claude Code, Cursor, Codex) treat
// the manifest as new and refresh installed copies. Empty falls back to
// the static default, preserving test ergonomics.
Version string
}
GenerateConfig holds org-level configuration for package generation.
type GitHubConfig ¶
type GitHubConfig struct {
Client GitHubPublisher
Org string
InstallationID int64
}
GitHubConfig holds the configured GitHub client and the Gram-owned org where plugin repos are created. Nil means GitHub publishing is disabled.
func NewGitHubConfig ¶
func NewGitHubConfig(in GitHubConfigInput) (*GitHubConfig, error)
NewGitHubConfig validates a GitHubConfigInput holistically and returns:
- (nil, nil) when no fields are set: feature is disabled
- (config, nil) when all fields are set: feature is enabled
- (nil, error) when only some fields are set: deployment is misconfigured
The all-or-nothing check prevents the silent-disable footgun where setting two of three inputs (e.g. forgetting GRAM_PLUGINS_GITHUB_ORG) leaves the deployment running with publishing inexplicably off.
type GitHubConfigInput ¶
GitHubConfigInput is the deployment-time configuration for plugin GitHub publishing. All fields must be set together (the feature is on) or all must be unset (the feature is off). Pass to NewGitHubConfig.
Client is constructed by the caller (typically once in cmd/gram, then shared with other consumers like the marketplace proxy that need to mint installation tokens against the same App).
type GitHubPublisher ¶
type GitHubPublisher interface {
CreateRepo(ctx context.Context, installationID int64, org, name string, private bool) error
PushFiles(ctx context.Context, installationID int64, owner, repo, branch, commitMsg string, files map[string][]byte) (string, error)
AddCollaborator(ctx context.Context, installationID int64, owner, repo, username, permission string) error
}
GitHubPublisher is the interface for creating repos and pushing files to GitHub.
type PluginInfo ¶
type PluginInfo struct {
Name string
Slug string
Description string
Servers []PluginServerInfo
}
PluginInfo contains the data needed to generate packages for a single plugin.
type PluginServerInfo ¶
type PluginServerInfo struct {
DisplayName string
Policy string
// Resolved MCP URL (e.g. https://app.getgram.ai/mcp/{slug}).
MCPURL string
// IsPublic indicates whether the toolset is publicly accessible (no Gram API key needed).
IsPublic bool
// EnvConfigs are user-facing environment variables for public servers.
EnvConfigs []ServerEnvConfig
}
PluginServerInfo contains the resolved information for a single MCP server.
type ServerEnvConfig ¶
type ServerEnvConfig struct {
VariableName string
DisplayName string // Shown to the user in Claude's userConfig prompt
}
ServerEnvConfig represents a user-facing environment variable required by a server.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
func NewService ¶
func (*Service) APIKeyAuth ¶
func (*Service) AddPluginServer ¶
func (s *Service) AddPluginServer(ctx context.Context, payload *gen.AddPluginServerPayload) (*gen.PluginServer, error)
func (*Service) CreatePlugin ¶
func (*Service) DeletePlugin ¶
func (*Service) DownloadCodexInstallScript ¶
func (s *Service) DownloadCodexInstallScript(ctx context.Context, payload *gen.DownloadCodexInstallScriptPayload) (*gen.DownloadCodexInstallScriptResult, io.ReadCloser, error)
func (*Service) DownloadObservabilityPlugin ¶
func (s *Service) DownloadObservabilityPlugin(ctx context.Context, payload *gen.DownloadObservabilityPluginPayload) (*gen.DownloadObservabilityPluginResult, io.ReadCloser, error)
DownloadObservabilityPlugin returns a ZIP of the per-org observability plugin for direct installation. Mints a fresh hooks-scoped API key per download and embeds it in the script — the org's API Keys page will accumulate one row per download, which admins can audit and revoke independently of the publish-bundled key. The plugin contents are otherwise identical to what PublishPlugins ships in the GitHub marketplace.
func (*Service) DownloadPluginPackage ¶
func (s *Service) DownloadPluginPackage(ctx context.Context, payload *gen.DownloadPluginPackagePayload) (*gen.DownloadPluginPackageResult, io.ReadCloser, error)
func (*Service) GetPublishStatus ¶
func (s *Service) GetPublishStatus(ctx context.Context, payload *gen.GetPublishStatusPayload) (*gen.PublishStatusResult, error)
func (*Service) ListPlugins ¶
func (s *Service) ListPlugins(ctx context.Context, payload *gen.ListPluginsPayload) (*gen.ListPluginsResult, error)
func (*Service) PublishPlugins ¶
func (s *Service) PublishPlugins(ctx context.Context, payload *gen.PublishPluginsPayload) (*gen.PublishPluginsResult, error)
func (*Service) RemovePluginServer ¶
func (*Service) SetPluginAssignments ¶
func (s *Service) SetPluginAssignments(ctx context.Context, payload *gen.SetPluginAssignmentsPayload) (*gen.SetPluginAssignmentsResult, error)
func (*Service) UpdatePlugin ¶
func (*Service) UpdatePluginServer ¶
func (s *Service) UpdatePluginServer(ctx context.Context, payload *gen.UpdatePluginServerPayload) (*gen.PluginServer, error)