Agent skill

Gram Pubsub Python

by speakeasy-api in speakeasy-api/gram

How to build and run GCP Pub/Sub stream subscribers in Python under pystreams/ — the multi command (start at pystreams/src/pystreams/cmd/multi.py), the graminfra.pubsub publisher/subscriber library…

AGPL-3.0Auto-check passedBackend & APIs

Install Gram Pubsub Python

skills CLI
$ npx skills add speakeasy-api/gram --skill gram-pubsub-python -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install speakeasy-api/gram gram-pubsub-python --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/speakeasy-api/gram.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/gram-pubsub-python .claude/skills/gram-pubsub-python && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
gram-pubsub-python
GitHub stars
272
Token cost
~4.1k tokens
SKILL.md length
1,897 words
Files
1
Skills in repo
39
Repo updated
First seen
Licence
AGPL-3.0

At a glance

How to build and run GCP Pub/Sub stream subscribers in Python under pystreams/ — the multi command (start at pystreams/src/pystreams/cmd/multi.py), the graminfra.pubsub publisher/subscriber library…

  • Works in 2 steps: write an async handler → register it in multi.py
  • The Python runtime that consumes them
  • SKILL.md covers Why Python exists here, and…, How the pieces fit, Read multi.py first and Adding a subscriber — the two…, plus 6 more sections
  • Calls mise and uv

What it does

Gram Pubsub Python is an agent skill from speakeasy-api/gram. How to build and run GCP Pub/Sub stream subscribers in Python under pystreams/ — the multi command (start at pystreams/src/pystreams/cmd/multi.py), the graminfra.pubsub publisher/subscriber library, and the anyio runtime mirroring the Go gram streams process. Activate for ANY Python Pub/Sub work in Gram: adding or changing a pystreams subscriber/handler, NLP/ML scanning consumers (Presidio PII detection, prompt-injection classifiers, spaCy/transformer models over streams), registering a receiver, the local…

Its SKILL.md is about 4.1k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Backend & APIs, covering Event-driven systems. It works with Python and Google Cloud. The repository describes itself as: Securely scale AI usage across your organization. A single stack to Connect, Secure, Observe and Distribute agents, MCPs, and Skills within your company. The licence is AGPL-3.0.

When your agent uses it

  • The Python runtime that consumes them
  • Tasks that involve Event-driven systems

Example prompts

  • “add a Presidio scanner”
  • “consume this topic in Python”
  • “wire up an ML handler”
  • “/gram-pubsub-python”

Requirements

  • Python 3

Workflow steps

2 steps, taken from the step headings in SKILL.md.

  1. write an async handler
  2. register it in multi.py

What it can do on your machine

Read from SKILL.md and the folder at commit 4d32da1. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • mise
    • uv

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use uv, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Gram Pubsub Python loads about 4.1k tokens when it runs. Until then it costs about 247 tokens; SKILL.md has 1,897 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~247
When it runs · the whole SKILL.md, loaded when a task matches
~4.1k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from speakeasy-api/gram at commit 4d32da1, republished under its AGPL-3.0 licence (© speakeasy-api). 1,897 words, ~4,135 tokens.

Download SKILL.mdSave it as .claude/skills/gram-pubsub-python/SKILL.md (or your agent's skills folder).
name
gram-pubsub-python
description
How to build and run GCP Pub/Sub stream subscribers in Python under `pystreams/` — the `multi` command (start at `pystreams/src/pystreams/cmd/multi.py`), the `gram_infra.pubsub` publisher/subscriber library, and the anyio runtime mirroring the Go `gram streams` process. Activate for ANY Python Pub/Sub work in Gram: adding or changing a `pystreams` subscriber/handler, NLP/ML scanning consumers (Presidio PII detection, prompt-injection classifiers, spaCy/transformer models over streams), registering a receiver, the local emulator for pystreams, or deciding whether a new consumer belongs in Go `streams` or Python `pystreams` — including phrasings like "add a Presidio scanner", "consume this topic in Python", "wire up an ML handler", or "why do we have Python in this monorepo" even when "pystreams" isn't named. Topic/subscription DECLARATION (proto options, `kcc.yaml`) lives in the `gram-pubsub` skill; use THIS skill for the Python runtime that consumes them.
metadata.relevant_files
pystreams/src/pystreams/**/*.py, pystreams/tests/**/*.py, pystreams/pyproject.toml, pystreams/Dockerfile.pystreams, infra/gram_infra/pubsub/*.py…

Gram Pub/Sub in Python (pystreams)

pystreams is the Python home for Pub/Sub stream consumers in the Gram monorepo. It runs alongside — not instead of — the Go gram streams process, and it consumes the same proto-declared Pub/Sub topology. This skill covers the Python runtime: how a subscriber is written, registered, and run. For declaring the topic/subscription itself (the (gcp.pubsub.v1.topic) / (gcp.pubsub.v1.subscription) proto options and infra/gen/kcc.yaml), use the gram-pubsub skill — that half is language-agnostic and shared.

Why Python exists here, and when to reach for it

The original and default stream-processing home is the Go streams component (server/cmd/gram/streams.go). Go's concurrency model and the GCP Pub/Sub Go SDK's use of it are substantially better suited to high-throughput message fan-out than the Python equivalent, async Python included. So the rule of thumb is: build new consumers in Go streams by default.

pystreams exists for the cases where Python's ecosystem is the deciding factor — overwhelmingly working with language models, transformers, NLP/ML use cases. Presidio (PII detection), prompt-injection classifier models, spaCy, and the transformer tooling these depend on are Python-first and have no comparable Go story. Reaching into that ecosystem from Go would mean reimplementing or shelling out; running the consumer in Python is the honest path. So the decision is not "which language do I prefer" but "does this consumer need a Python-only library to do its job?" If yes, pystreams; if no, Go streams.

The first real pystreams consumer is the Presidio PII scanner (pystreams/src/pystreams/risk/handler.py); ping is a heartbeat used to keep the publish→subscribe path exercised, mirroring the Go ping.

How the pieces fit

infra/proto/**.proto            topic/subscription declarations (shared, see gram-pubsub)
  └─ buf generate ─┬─ infra/gen/**        Go types  + infra/gen/kcc.yaml
                   └─ infra/gen_py/**      Python types (gram.*.v1.*_pb2)

infra/gram_infra/pubsub/        the Python publisher/subscriber library
  ├─ broker.py                  PubSubBroker / EmulatedPubSubBroker (mirrors infra/pkg/gcp)
  ├─ publisher.py               Publisher[M], pubsub_publisher_for_message
  ├─ subscriber.py              Subscriber[M], pubsub_subscriber_for_message
  └─ discover.py                proto-option → resource-name resolution

pystreams/                      the runnable service ("multi" command)
  └─ src/pystreams/cmd/multi.py the entrypoint — START HERE

infra/gram_infra (the gram-infra package) is a uv workspace member shared by pystreams; it holds both the generated Python protobufs and the hand-written Pub/Sub convenience layer. pystreams is the deployable that wires handlers onto subscriptions and runs the receive loops. Read the library as the Python counterpart of infra/pkg/gcp/ — the docstrings deliberately point back to the Go files they mirror, so the two layers stay behaviorally aligned.

Read multi.py first

pystreams/src/pystreams/cmd/multi.py is the whole service in one screen. It is a Click command (multi) that anyio.runs an async multi(...) coroutine. Walking it top to bottom teaches the runtime:

  1. Configure logging (structlog) with service attributes.
  2. Pick a project id: real --gcp-project-id, or a throwaway when an emulator host is set (the emulator doesn't care about the project).
  3. Build a broker (_build_broker): EmulatedPubSubBroker when --pubsub-emulator-host is set (it reconciles topics/subscriptions on demand, since the emulator has no Config Connector), else PubSubBroker (assumes Config Connector already provisioned everything). This is the exact prod-vs-local split the Go layer makes.
  4. Enter the broker as a context manager (with broker:) — it owns the publisher/subscriber clients and flushes + closes them on exit, including a clean Ctrl-C teardown.
  5. Open one anyio task group and start, in order: a signal handler that cancels the group on SIGINT/SIGTERM, the event-loop-lag monitor, the health server (awaited so it's bound before consuming begins), then the ReceiverGroup.
  6. Register receivers, one receivers.receive(...) call per subscription.
  7. Flip readiness on (health_state.set_ready()) only after receivers are wired, so /readyz doesn't go green before the service can actually consume.

The structured-concurrency shape matters: everything runs as a child task of that single task group, so any fatal error or a shutdown signal tears the whole process down together for a clean restart — the Python analogue of the Go errgroup in streams.go.

Adding a subscriber — the two steps

Exactly like the Go side: write a handler, then register it.

Step 1 — write an async handler

A handler is an async callable (message, meta) -> None. The proto message type is the topic's payload; meta is gram_infra.pubsub.subscriber.MessageMetadata (id, attributes, delivery_attempt). The return/raise is the ack/nack signal, identical to Go: returning normally acks; raising nacks (triggering redelivery and eventual dead-lettering if the subscription declares a dead_letter policy). You never call ack()/nack() yourself in the callback form — the library does it from your handler's outcome.

The minimal shape is PingHandler (pystreams/src/pystreams/ping/handler.py): a class holding its dependencies, with an async def handle(self, message, meta). Register handle (the bound method), not the class.

The real reference is PresidioHandler (pystreams/src/pystreams/risk/handler.py). It demonstrates the patterns that matter for ML/NLP consumers:

  • Load the model once, reuse across messages. Constructing Presidio's AnalyzerEngine loads a spaCy model — expensive. Do it in __init__, not per delivery.
  • Run CPU-bound work off the event loop. This is the Python-specific hazard. anyio runs everything on one event-loop thread; a synchronous, CPU-bound call (model inference, regex over large text) that doesn't await will stall every other subscription until it returns. Wrap such work with asyncer.asyncify(...) so it runs in a worker thread and the loop stays responsive. The loop-lag monitor exists precisely to make this kind of stall visible before it becomes an outage.
  • Make heavy dependencies injectable behind a Protocol. PresidioHandler depends on a narrow Analyzer protocol, so tests inject a lightweight fake instead of loading the NLP model (see pystreams/tests/test_risk_handler.py).
  • Decide ack/nack deliberately, especially when no DLQ policy is declared. The PresidioScanner subscription declares no dead_letter policy, so a raised exception would nack and redeliver the same message for the full retention window — one poison input could loop for 30 days. Because this is best-effort shadow processing, the handler swallows Exception and returns (acking) rather than poisoning the subscription, logging the error type only. Catch Exception, never BaseException, so cancellation (graceful shutdown) still propagates. Match the policy to intent: raise only when you genuinely want the message retried.
  • Never log PII or sensitive data. PII/security handlers log entity types and counts, request ids, and delivery attempts — never the text or the matches. An error string or traceback can echo the input, which is why the failure path logs type(exc).__name__ and not the exception message.
Step 2 — register it in multi.py

Add a receivers.receive(...) call in the marked block, mirroring the topic and subscription proto declarations:

python
receivers.receive(
    presidio_request_pb2.PresidioRequest,  # the TOPIC message type → fixes the handler's `message` type
    presidio_scanner_pb2.PresidioScanner,  # the SUBSCRIPTION marker message (carries the subscription option)
    PresidioHandler(logger).handle,        # your async handler callback
)

The three arguments line up one-to-one with the proto options the gram-pubsub skill describes: the topic-declaring message, the subscription-declaring marker, and the handler. ReceiverGroup.receive (pystreams/src/pystreams/cmd/receiver.py) resolves a Subscriber via pubsub_subscriber_for_message, wraps your handler in per-message tracing (deps/tracing.py — a stream.handleMessage span tagged with the topic/subscription proto names, continuing the publisher's trace via W3C context), and starts the receive loop as a child task. It's the direct analogue of mustReceive/receiverGroup in streams.go, so each subscription is one line at the call site.

Go and Python can consume the same topic through separate subscriptions: gram.ping.v2.Message has both a Processor marker (consumed by Go) and a PyProcessor marker (consumed by pystreams). If you want a Python consumer of a topic the Go side already reads, declare a new subscription marker rather than stealing the existing one. Declaration is a gram-pubsub task.

Show full SKILL.md (793 more words)Show less
What the receive loop gives you for free

Subscriber.receive (infra/gram_infra/pubsub/subscriber.py) handles the hard parts so handlers stay tiny: it unmarshals the payload into a fresh proto instance (a malformed payload is nacked and never reaches you), runs handlers concurrently up to a bounded max_concurrency, isolates a raised handler error to that one message (logged with context, then nacked), bridges the google-cloud-pubsub library's background threads onto the event loop without parking a worker thread per subscriber, and tears down cleanly on cancellation — nacking anything buffered-but-undispatched so the broker redelivers immediately instead of waiting out the ack deadline. There is also a Subscriber.stream() async-iterator form for explicit per-message ack/nack, but receive (the callback form) is what pystreams uses; prefer it.

Publishing from Python (rare)

Most events are published by the Go server where they originate. When Python does need to publish, use pubsub_publisher_for_message(broker, MessageType) → await publisher.publish(msg) (infra/gram_infra/pubsub/publisher.py). It proto-marshals the body and tags it with content-type: application/x-protobuf and schema: <proto full name> — the same two attributes the Go publisher sets — so messages are interoperable across languages, and it injects W3C trace context so a Python→Python or Go→Python hop continues the trace. publish is a coroutine; await it.

Local development

pystreams runs locally against the shared Pub/Sub emulator — no Config Connector, no real GCP.

  • Start it: pitchfork start pystreams-multi or the pitchfork mcp server if available (runs uv run multi in the pystreams/ dir).
  • Emulator: mise.toml sets PUBSUB_EMULATOR_HOST (and the pubsub-emulator compose service the Go side uses is the same one). With that env var set, multi builds an EmulatedPubSubBroker, which lazily creates the topic and subscription on first use — so you don't provision anything locally.
  • Health/control server: binds GRAM_PYSTREAMS_CONTROL_HOST/PORT (default 127.0.0.1:8089), serving GET /healthz (liveness, always 200) and GET /readyz (503 until receivers are wired, then 200; flips back to 503 the instant shutdown begins so a rolling deploy drains in-flight handlers).
  • Env vars: service config (GRAM_SERVICE_VERSION, GRAM_ENVIRONMENT, GRAM_LOG_LEVEL, GRAM_LOG_PRETTY) and GCP config (GRAM_GCP_PROJECT_ID, PUBSUB_EMULATOR_HOST) all have CLI flags too; see cmd/flags_*.py.

Testing and linting

  • Tests: mise run test:pystreams (pytest, asyncio_mode = "auto" so async tests need no decorator). Tests exercise handlers with fakes/protocols and the structlog capture helper — no live broker or model load. Follow that: inject a fake analyzer/dependency and assert on captured logs and ack/nack behavior. (Per repo convention, the broker/subscriber library tests also run under anyio's trio backend, not just asyncio, to keep them backend-agnostic.)
  • Lint/type-check: mise run lint:pystreams runs ty check and pyrefly check. Both are strict; keep handlers fully typed.
  • Format: hk fix formats changed files (Python included) across the branch.

Generated protobufs

mise run gen:infra runs buf generate, which emits both Go (infra/gen/) and Python (infra/gen_py/, via the protocolbuffers/python + pyi plugins). Import the Python types as from gram.<pkg>.v1 import <name>_pb2 and the library as from gram_infra.pubsub import .... After any change to a .proto under infra/proto/, regenerate and commit per the gram-pubsub skill — the Python side picks up the new _pb2 modules from the same run. The protobuf runtime floor is pinned to match buf's generator version (see infra/pyproject.toml); keep them in lockstep if the buf plugin version changes.

Observability

Tracing, logging, and the loop-lag metric are wired through OpenTelemetry's API and structlog. The per-message span and W3C propagation mirror the Go receiver exactly (deps/tracing.py). Note that until a TracerProvider/MeterProvider is installed in the process, the OTel instruments resolve to the API's implicit no-ops — recording stays cheap and correct, and the data flows out once a provider is configured, with no change to handler code. So don't be surprised if spans/metrics aren't exported yet; the wiring is provider-agnostic by design.

Gotchas and conventions

  • Default to Go streams. Only add a consumer here when it genuinely needs a Python-only library (NLP/ML). Most other use cases belong in streams.go.
  • Never block the event loop. Wrap any synchronous CPU-bound call in asyncify / anyio.to_thread.run_sync. A blocking handler stalls all subscriptions on the same loop. The loop-lag histogram is your early warning.
  • Build expensive resources once, in the handler's __init__, not per message.
  • Match ack/nack to intent. Return to ack, raise to nack. For best-effort work with no DLQ, prefer acking (swallow Exception, log, return) so one bad message can't poison the subscription for the whole retention window. Always let cancellation (BaseException) propagate.
  • Don't leak content. Security/PII handlers log entity types, counts, and ids — never scanned text, matched values, or raw error strings/tracebacks.
  • Declaration is a gram-pubsub task. Adding a topic or subscription means editing a .proto and running mise run gen:infra — not editing pystreams. Use a new subscription marker (e.g. a Py* variant) for a Python consumer of an already-consumed topic.
  • Build the image from the repo root, not from pystreams/ — pystreams is a uv workspace member that depends on gram-infra, and the single uv.lock lives at the root (see the header of Dockerfile.pystreams).

© speakeasy-api, AGPL-3.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .agents/skills/gram-pubsub-python of speakeasy-api/gram.

Open the folder on GitHubat commit 4d32da1

Compare with similar skills

Gram Pubsub Python next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Gram Pubsub Python compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Gram Pubsub Python this skillspeakeasy-api/gram272—~4.1kAutomated safety check: PassAGPL-3.0
Io ConnectorsKilo-Org/kilo-marketplace189—~1.3kAutomated safety check: PassApache-2.0
AWS Serverless Edazxkane/aws-skills3674 repos~3.2kAutomated safety check: PassMIT
Windmill Trigger Type Checklistwindmill-labs/windmill18k—~4.7kAutomated safety check: PassCustom licence
Opensource Guide Coachcalf-ai/calfkit-sdk1491 repos~2.1kAutomated safety check: PassApache-2.0
Azure Event Hubs Python SDK Guidemicrosoft/skills3.1k1 repos~2.3kAutomated safety check: PassMIT

Similar skills

  • Io Connectors

    Kilo-Org/kilo-marketplace

    Guides development and usage of I/O connectors in Apache Beam.

    189 GitHub stars~1.3k tokensUpdated 9 days ago
    Testing & QAAuto-check passed
  • AWS Serverless Eda

    zxkane/aws-skills

    AWS serverless and event-driven architecture expert based on Well-Architected Framework.

    367 GitHub starsUsed in 4 repos~3.2k tokens
    Backend & APIsAuto-check passed
  • Windmill Trigger Type Checklist

    windmill-labs/windmill

    Checklist of every backend, frontend, CLI and capture change needed to add a new TriggerCrud-based trigger type, such as Azure, GCP or Kafka, to Windmill.

    18k GitHub stars~4.7k tokensUpdated today
    Backend & APIsAuto-check passed
  • Opensource Guide Coach

    calf-ai/calfkit-sdk

    A skill your agent uses when a user wants guidance on starting, contributing to, growing, governing, funding, securing, or sustaining an open source project, or asks about contributor onboarding…

    149 GitHub starsUsed in 1 repo~2.1k tokens
    Backend & APIsAuto-check passed
  • Official

    Covers producer, consumer, and checkpoint-store setup for Azure Event Hubs streaming in Python, with Entra ID auth and partition targeting.

    3.1k GitHub starsUsed in 1 repo~2.3k tokens
    Backend & APIsAuto-check passed
  • Polylith Base Creation

    DavidVujic/python-polylith

    Create a Polylith base with poly create base — the entry point of a deployable application (HTTP API, CLI, message-queue consumer, AWS Lambda handler, GCP Cloud Function, scheduled job).

    553 GitHub stars~757 tokensUpdated 3 days ago
    Backend & APIsAuto-check passed

More from speakeasy-api/gram

All 39 skills in this repo
  • Gram Playwright CLI

    speakeasy-api/gram

    A skill your agent uses when automating the Gram dashboard in a browser, capturing screenshots, inspecting pages.

    272 GitHub stars~3.4k tokensUpdated today
    Auto-check passed
  • Transactional Email

    speakeasy-api/gram

    A skill your agent uses when adding, changing, restyling, reviewing, validating, or previewing a Gram/Speakeasy transactional email, in Go or in LMX/MJML — a template<name.go, a TemplateKey…

    272 GitHub stars~4.7k tokensUpdated today
    Auto-check passed
  • Admin Shadcn

    speakeasy-api/gram

    A skill your agent uses when adding, changing, or styling UI in client/admin (the Gram admin dashboard) that touches shadcn/ui — a button, dialog, table, sidebar, badge, select, tabs, tooltip, card…

    272 GitHub stars~1k tokensUpdated today
    Auto-check passed
  • A skill your agent uses when adding, editing, reviewing, testing, or locating a reviewed skill distributed with the Platform MCP plugin; triggers include "Platform MCP skill", "platformmcpskills"…

    272 GitHub stars~2.2k tokensUpdated today
    Auto-check passed
  • Clickhouse

    speakeasy-api/gram

    A skill your agent uses when changing or reviewing Gram ClickHouse schemas, migrations, queries, inserts, access principals, bootstrap SQL, Cloud compatibility, partial migration failures, or…

    272 GitHub stars~3.2k tokensUpdated today
    Auto-check passed
  • Feature Flag

    speakeasy-api/gram

    A skill your agent uses when gating a feature behind a flag, dogfooding or gradually rolling out a change, choosing between productfeatures and PostHog feature flags, adding or checking a product…

    272 GitHub stars~2.6k tokensUpdated today
    Auto-check passed

Categories

Questions about Gram Pubsub Python

What does Gram Pubsub Python do?

How to build and run GCP Pub/Sub stream subscribers in Python under pystreams/ — the multi command (start at pystreams/src/pystreams/cmd/multi.py), the graminfra.pubsub publisher/subscriber library…. Gram Pubsub Python is an agent skill from speakeasy-api/gram.pubsub publisher/subscriber library, and the anyio runtime mirroring the Go gram streams process.

When should I use Gram Pubsub Python?

Gram Pubsub Python fits situations like: the Python runtime that consumes them; tasks that involve Event-driven systems.

How do I install Gram Pubsub Python in Claude Code?

Run `npx skills add speakeasy-api/gram --skill gram-pubsub-python -a claude-code`. Or copy the skill folder (.agents/skills/gram-pubsub-python in speakeasy-api/gram) into .claude/skills/gram-pubsub-python in your project. Claude Code loads it when a task matches its description.

How do I install Gram Pubsub Python in Codex?

Run `npx skills add speakeasy-api/gram --skill gram-pubsub-python -a codex`. Or copy the skill folder (.agents/skills/gram-pubsub-python in speakeasy-api/gram) into .agents/skills/gram-pubsub-python in your project. Codex loads it when a task matches its description.

Can I use Gram Pubsub Python in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add speakeasy-api/gram --skill gram-pubsub-python -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/gram-pubsub-python, .gemini/skills/gram-pubsub-python, .github/skills/gram-pubsub-python and .opencode/skills/gram-pubsub-python in your project.

What does Gram Pubsub Python need to run?

Going by SKILL.md and its folder, Gram Pubsub Python needs the command-line tools its instructions call (mise and uv). Our summary lists: Python 3.

Does Gram Pubsub Python access the network?

SKILL.md contains no URLs. Its commands use uv, which can reach the network depending on how they are called. This is read from the text; nothing was executed.

Is Gram Pubsub Python safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Gram Pubsub Python use?

Gram Pubsub Python is published under the AGPL-3.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Gram Pubsub Python use?

About 4.1k tokens (SKILL.md is roughly 17k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Gram Pubsub Python?

Skills that share tags, products or a category with Gram Pubsub Python: Io Connectors (Kilo-Org/kilo-marketplace, 189 stars), AWS Serverless Eda (zxkane/aws-skills, 367 stars), Windmill Trigger Type Checklist (windmill-labs/windmill, 18k stars) and Opensource Guide Coach (calf-ai/calfkit-sdk, 149 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Gram Pubsub Python?

speakeasy-api (a GitHub organization) maintains it in speakeasy-api/gram, which has 272 GitHub stars. The repository holds 39 skills in this directory. The repository was last updated on October 7, 2026.

Source: speakeasy-api/gram on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.