Pullboard
A work board that lives in your git repo. Agents pick up the next task, another agent checks it, and you barely explain a thing. Local, open source, no account.
翻譯準備中
製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗Documentation · Installation · Quick start · CLI · AI / agents
pyfsr is a batteries-included Python client for the FortiSOAR REST API. It gives you a typed query/CRUD layer over any module, picklist resolution, connector execution, playbook-run history, safe deletes -- and a ready-made AI/agent surface (tool-schema registry + an optional MCP server) so an agent can drive FortiSOAR with no glue code.
There's also a pyfsr CLI for the things you reach for outside a script:
poking at an appliance's health and services, and authoring playbooks in YAML
and pushing them to a live instance.
Python 3.10+ · Pydantic v2 · MIT.
pip install pyfsr
# with the optional generic MCP server:
pip install 'pyfsr[mcp]'
from pyfsr import FortiSOAR, Query
# API-key auth, or ("username", "password")
client = FortiSOAR("soar.example.com", "your-api-key")
# Generic, typed CRUD for ANY module via client.records(module)
incidents = client.records("incidents")
inc = incidents.get("0d2c...") # by uuid, "module:uuid", or full IRI
inc["name"], inc.uuid # records are dict- AND attribute-accessible
# Structured queries with a fluent builder -> a HydraPage you can iterate
page = incidents.query(
Query().eq("status.itemValue", "Open").like("name", "phish").limit(50)
)
for inc in incidents.iterate(Query().eq("status.itemValue", "Open")):
... # lazily walks every page
# Create / update / delete (soft by default; hard= for permanent)
new = incidents.create({"name": "Suspicious login", "severity": "High"},
resolve_picklists=True) # friendly values -> IRIs
incidents.update(new.uuid, {"status": "Closed"}, resolve_picklists=True)
incidents.delete(new.uuid) # delete(..., hard=True) to purge
from pyfsr import EnvConfig
# reads FSR_BASE_URL (+ FSR_API_KEY or FSR_USERNAME/FSR_PASSWORD),
# FSR_PORT, FSR_VERIFY_SSL, FSR_TIMEOUT
client = EnvConfig.from_env().client()
client.records(module) for CRUD on any module;
no hand-built /api/3/... URLs or Hydra unwrapping.Query().eq(...).in_(...).group(...).sort(...).limit(...),
compiled to the FortiSOAR query-body shape (pagination handled for you).BaseRecord, so custom fields/modules never break.client.picklists resolves friendly values ("High") to
IRIs and discovers which picklist a (module, field) binds to.client.connectors lists configured connectors, runs
healthchecks, and executes operations.client.playbooks merges live + historical run history and
resumes manual-input steps.client.list_modules() / client.describe_module().timeout=, automatic retry with
backoff on idempotent requests (429/5xx), and secrets masked in verbose logs.pyfsr.spec.load_spec() for offline reference and
drift(client) to compare the spec against a live appliance.The agent layer (tool registry, MCP server, workflows) lives in
fsr-agentic-toolkit; the
pyfsr-mcp command hands off to it when it is installed.
Reads accept summary=True or fields=[...] to keep payloads small:
client.records("alerts").query(Query().limit(20), summary=True)
Point any MCP-capable agent at any FortiSOAR with one command:
pip install 'pyfsr[mcp]'
FSR_BASE_URL=soar.example.com FSR_API_KEY=... python -m pyfsr.agent.mcp
It exposes the same registry (record CRUD, schema discovery, picklists, connectors, playbook runs) as MCP tools -- generic and dependency-light, distinct from any domain-specific FortiSOAR MCP.
Installing pyfsr puts a pyfsr command on your path with seven groups.
pyfsr instances -- inspect the named-instance registry
(~/.pyfsr/instances.toml), which is what every --instance flag resolves
against:
pyfsr instances list # every alias: base URL, auth kind, SSH profile
pyfsr instances show 206 # one instance's resolved settings (no secrets)
pyfsr instances check # connect to each box; exit 1 if any fails
check probes the version endpoint and then an authenticated read, so a
registered-but-broken alias shows up as unreachable or auth-failed before a
script fails on it.
pyfsr appliance -- operational verbs against a FortiSOAR box (most run over
SSH/sudo and stay dependency-light on the far end):
pyfsr appliance info # host, version, content DB, device UUID
pyfsr appliance host # mem / swap / load / per-service RSS / disk
pyfsr appliance service restart cyops-postman --yes
pyfsr appliance db # Postgres verbs, multi-DB aware
pyfsr appliance es # Elasticsearch health + shard state
pyfsr appliance license # licensing / identity, drift check
pyfsr appliance content-hub sync # pull the Content Hub catalog + artifacts
Other appliance subgroups: mq (RabbitMQ), ha, certs, logs, and
diagnose (runs fsr_diagnose.sh). --help on any of them lists the verbs.
pyfsr playbook -- author playbooks as YAML and deploy them:
pyfsr playbook steps # list every step type you can write
pyfsr playbook step-help TYPE # keys + a compiling example for one type
pyfsr playbook examples # foundational playbook library (--intent/--stage/--manifest)
pyfsr playbook show SLUG # print one library playbook's metadata + YAML
pyfsr playbook validate flow.yaml # compile + report diagnostics (offline)
pyfsr playbook compile flow.yaml # emit the FSR import envelope (offline)
pyfsr playbook lint flow.yaml # live preflight: connector steps missing config
pyfsr playbook deploy flow.yaml # compile and create it on the appliance
pyfsr records -- query and manage FortiSOAR records over the API:
pyfsr records alerts [--status Open] [--severity High]
pyfsr records incidents '<field=value or Query DSL JSON>'
pyfsr records delete <module> <uuid...> [--yes]
pyfsr repo -- discover and download from Fortinet's content repo (no
appliance needed).
pyfsr widget -- upload and publish widgets on a live appliance.
pyfsr mcp -- call FortiSOAR's own native MCP tool gateway
(list-tools / call), distinct from the generic pyfsr.agent.mcp server.
uv sync
uv run pytest -q # unit tests (live tests deselected by default)
uvx ruff check src tests
Live integration tests run with pytest -m integration against the instance
named by FSR_INSTANCE (an alias from ~/.pyfsr/instances.toml), the FSR_*
environment variables, or examples/config.toml, in that order. The AI tests
(test_ai_integration.py) make no LLM calls, so they spend no AI tokens.
MIT -- see LICENSE.