Imported from pipefy/terraform-provider-pipefy (
AGENTS.md). Install upstream withnpx skills add pipefy/terraform-provider-pipefy. Copyright stays with the author.
AGENTS.md
Development guide for terraform-provider-pipefy, aimed at both humans and AI coding agents. CLAUDE.md is a symlink to this file.
Project overview
A Terraform provider that manages Pipefy resources through the Pipefy GraphQL API (https://api.pipefy.com/graphql). It is built on the Terraform Plugin Framework and speaks Terraform plugin protocol 6.0.
Module path: github.com/pipefy/terraform-provider-pipefy. Registry source: pipefy/pipefy.
It exposes eleven resources (pipefy_pipe, pipefy_phase, pipefy_field, pipefy_field_condition, pipefy_automation, pipefy_label, pipefy_pipe_relation, pipefy_webhook, pipefy_ai_agent, pipefy_table, pipefy_table_field, all importable) and two data sources (pipefy_pipe, pipefy_phase).
Setup and requirements
- Go >= 1.24 (pinned to 1.24.0 in
.tool-versionsandgo.mod) - Terraform >= 1.0
golangci-lintfor linting
git clone https://github.com/pipefy/terraform-provider-pipefy
cd terraform-provider-pipefy
go mod download
make build
Essential commands
All tasks run through the GNUmakefile. Use these targets rather than ad hoc go invocations.
| Command | What it does |
|---|---|
make build |
Compile all packages (go build -v ./...) |
make install |
Build and install the provider into $GOPATH/bin |
make generate |
Regenerate registry docs via tfplugindocs (cd tools; go generate ./...) |
make fmt |
Format Go code (gofmt -s -w -e .) |
make lint |
Run golangci-lint run |
make test |
Run unit tests |
make testacc |
Run acceptance tests (TF_ACC=1) against the live API |
The docs/ directory is generated. Run make generate after any schema change; never hand-edit files under docs/.
Project layout
internal/pipefy/ # API layer: every GraphQL document, one service per entity, typed errors
internal/locks/ # Mutex helpers for serializing API mutations the API cannot take concurrently
internal/provider/
provider.go # Provider config, auth, resource/data-source registration
resources/ # pipe, phase, field, automation, label, pipe_relation, webhook, ai_agent, field_condition, table, table_field
datasources/ # pipefy_pipe, pipefy_phase
client/api_client.go # Pipefy GraphQL HTTP transport
conditionschema/ # Terraform-side model for the shared condition block
validators/ # Reusable attribute validators
examples/ # Example .tf per resource and data source (feeds the docs)
docs/ # Generated reference docs (do not edit by hand)
tools/ # tfplugindocs tooling for `make generate`
main.go # Provider entrypoint
internal/pipefy is the API layer and imports no Terraform packages, so it is testable against
httptest with no Terraform harness. Resources hold schema, plan and state handling, and
diagnostics, and call the SDK for everything else.
Conventions
- Terraform attribute names are snake_case; resource type names are prefixed
pipefy_. - Name every GraphQL operation with a descriptive PascalCase name and a
_tfsuffix:Get*for queries,Create*/Update*/Delete*for mutations, naming the entity and the action (query GetPipe_tf($id:ID!){ ... },mutation CreateLabel_tf(...)). The_tfmarker identifies the request as provider traffic in server-side traces and logs. Each request carries one operation, so the name in the document is enough; no separateoperationNamefield is needed. - Register every resource and data source in
provider.govia theResources()andDataSources()constructor lists. - Each resource has a matching example at
examples/resources/<type>/resource.tfand animport.sh; data sources haveexamples/data-sources/<type>/data-source.tf. These examples are embedded into the generated docs. - Auth lives entirely in
provider.go'sConfigure. The provider accepts a statictoken(envPIPEFY_TOKEN) or a service accountclient_id+client_secret(envPIPEFY_CLIENT_ID/PIPEFY_CLIENT_SECRET); exactly one mode must be configured.
How to add a resource
- Add the entity to the SDK in
internal/pipefy/<name>.go: the GraphQL documents, wire structs, input structs, and a service with typed methods. Register the service inNewininternal/pipefy/client.goand cover the methods withhttptesttests. Nothing in this package imports Terraform. Two gates hold that boundary in place, and both run in CI:depguardrejects a Terraform orinternal/providerimport from inside the SDK, andTestNoGraphQLOutsideSDKininternal/provider/architecture_test.gofails if a named GraphQL operation appears anywhere else. - Implement schema,
Create,Read,Update,Delete, andImportStateininternal/provider/resources/resource_<name>.go, calling the SDK. Resources hold no GraphQL documents.Readcallsresp.State.RemoveResourcewhen the SDK returnspipefy.ErrNotFound. - Add its constructor to the
Resources()list ininternal/provider/provider.go. - Add
examples/resources/pipefy_<name>/resource.tfandimport.sh. - Add an acceptance test
internal/provider/resource_<name>_test.go. - Run
make generateto refreshdocs/, thenmake testaccto verify.
Testing
- Unit tests:
make test. - Acceptance tests are gated on
TF_ACC=1(usemake testacc). They create real Pipefy resources and may incur cost. - Export credentials before running acceptance tests:
PIPEFY_TOKEN, orPIPEFY_CLIENT_IDandPIPEFY_CLIENT_SECRET.
Gotchas
- One of the two auth modes is required; the provider errors at configure time if neither is set.
- Single-tenant deployments must set both
endpointandtoken_urlto the tenant domain.
Never
- Commit API tokens, client secrets, or other credentials.
- Hand-edit generated files under
docs/; change the schema and runmake generateinstead.
API Interaction and Resource Validation
To ensure the provider remains maintainable as the SaaS platform evolves, adhere to the following guidelines regarding resource attributes and validation:
1. Attribute Validation Strategy
- Decision Framework:
- Use Enums: Only when the attribute values are canonical and highly stable. This provides superior DX (IDE autocomplete, instant feedback) while accepting the occasional need for provider updates.
- Use Strings (Free-Text): When values are volatile or frequently updated by the SaaS API. This avoids breaking changes in the provider.
- Use Regex for Strings: Even for volatile strings, implement a a high level validation with Regex if the data format is predictable. This prevents malformed data from reaching the API while maintaining flexibility.
- Reusable Validators: Do not reinvent the wheel for standard validations. Create and maintain a library of "generic" validators (e.g.,
IsOneOf,MatchesRegex,IsUUID) within the provider's internal package. These should be reused across multiple resources to ensure consistent behavior and standardized error messages across the entire provider. - Dynamic Discovery: When users need to verify valid options for volatile attributes, encourage the use of Data Sources that fetch the current list directly from the API.
- Error Handling: If an input is invalid, rely on the backend API’s response to inform the user. When implementing the provider, ensure that API error messages are surfaced clearly to the user, mapping generic HTTP errors to actionable feedback.
2. Documentation Standards
When defining resource attributes that are subject to backend change:
- Do not include static lists of values in descriptions, as these will quickly go stale.
- Use "Evergreen" Descriptions: Point users to the official SaaS API documentation for the source of truth regarding valid values.
- Pipefy's official API documentation can be found at: https://developers.pipefy.com/reference
- Example format:
action: (String) The event that triggers this webhook. Supported values are defined by the SaaS platform. Please refer to [Link to API Documentation] for the current list of available actions.
3. Plan-Time vs. Apply-Time
- Plan-Time: Only perform client-side validation for static, deterministic constraints (e.g., regex patterns for name formats, field length, or logical exclusivity between two local fields).
- Apply-Time: Defer checks for existence, permissions, and dynamic business logic to the Apply phase (API calls). This minimizes the risk of the provider being out-of-sync with the SaaS environment.