Phoenix API Generator

Generate a full Phoenix JSON API from an OpenAPI spec or natural language description. Creates contexts, Ecto schemas, migrations, controllers, JSON views/renderers, router entries, ExUnit tests with factories, auth plugs, and tenant scoping. Use when building a new Phoenix REST API, adding CRUD endpoints, scaffolding resources, or converting an OpenAPI YAML into a Phoenix project.

MIT-0 · Free to use, modify, and redistribute. No attribution required.
1 · 1.5k · 2 current installs · 2 all-time installs
MIT-0
Security Scan
VirusTotalVirusTotal
Benign
View report →
OpenClawOpenClaw
Benign
high confidence
Purpose & Capability
The name/description (Phoenix API Generator) match the SKILL.md and the included reference files (Phoenix conventions, Ecto patterns, test patterns). There are no unrelated credentials, binaries, or install steps requested — everything present is relevant to scaffolding a Phoenix app.
Instruction Scope
The SKILL.md describes parsing OpenAPI or natural-language input, generating migrations, schemas, contexts, controllers, tests, and auth plugs, and instructs the agent to ask the user before writing files. It does not instruct reading unrelated system files or secrets. However, it is vague about the target filesystem path, backup/rollback behavior, and conflict resolution for existing files — you should ensure the skill will write only in the intended project directory and that generated files are reviewed before committing.
Install Mechanism
No install spec is provided and the skill is instruction-only, so nothing is downloaded or written to disk by an installer. This is the lowest-risk install model.
Credentials
The skill declares no required environment variables, credentials, or config paths. The examples reference common runtime functions (e.g., System.unique_integer, Ecto.UUID.generate) but do not attempt to access secret environment variables or unrelated system configuration.
Persistence & Privilege
The skill is not marked always:true and requests no persistent system modification beyond writing generated project files when invoked. The platform default allows autonomous invocation (disable-model-invocation: false); if you are concerned about an agent invoking file-write operations without supervision, consider disabling autonomous invocation for this skill or requiring explicit confirmation before any writes.
Assessment
This skill appears to be a coherent Phoenix code generator and does not request secrets or downloads. Before using it: (1) run it in a safe/sandbox project or a new git branch so you can review and revert generated files; (2) confirm the intended output path and that the skill will prompt before writing; (3) review generated auth plugs and token verification code — the skill scaffolds patterns but you must integrate secure token/key handling and secrets management yourself; (4) run your test suite and linters on generated code; (5) if you do not want an agent to create files autonomously, disable automatic invocation or require an explicit manual step. Overall the skill is internally consistent, but always review and test generated code before deploying.

Like a lobster shell, security has layers — review code before you run it.

Current versionv1.0.0
Download zip
latestvk972tza2hn659bxkq5b8mhaekx80f1da

License

MIT-0
Free to use, modify, and redistribute. No attribution required.

SKILL.md

Phoenix API Generator

Workflow

From OpenAPI YAML

  1. Parse the OpenAPI spec — extract paths, schemas, request/response bodies.
  2. Map each schema to an Ecto schema + migration.
  3. Map each path to a controller action; group by resource context.
  4. Generate auth plugs from securitySchemes.
  5. Generate ExUnit tests covering happy path + validation errors.

From Natural Language

  1. Extract resources, fields, types, and relationships from the description.
  2. Infer context boundaries (group related resources).
  3. Generate schemas, migrations, controllers, views, router, and tests.
  4. Ask the user to confirm before writing files.

File Generation Order

  1. Migrations (timestamps prefix: YYYYMMDDHHMMSS)
  2. Ecto schemas + changesets
  3. Context modules (CRUD functions)
  4. Controllers + FallbackController
  5. JSON renderers (Phoenix 1.7+ *JSON modules, or *View for older)
  6. Router scope + pipelines
  7. Auth plugs
  8. Tests + factories

Phoenix Conventions

See references/phoenix-conventions.md for project structure, naming, context patterns.

Key rules:

  • One context per bounded domain (e.g., Accounts, Billing, Notifications).
  • Context is the public API — controllers never call Repo directly.
  • Schemas live under contexts: MyApp.Accounts.User.
  • Controllers delegate to contexts; return {:ok, resource} or {:error, changeset}.
  • Use FallbackController with action_fallback/1 to handle error tuples.

Ecto Patterns

See references/ecto-patterns.md for schema, changeset, migration details.

Key rules:

  • Always use timestamps(type: :utc_datetime_usec).
  • Binary IDs: @primary_key {:id, :binary_id, autogenerate: true} + @foreign_key_type :binary_id.
  • Separate create_changeset/2 and update_changeset/2 when create/update fields differ.
  • Validate required fields, formats, and constraints in changesets — not in controllers.

Multi-Tenancy

Add tenant_id :binary_id to every tenant-scoped table. Pattern:

# In context
def list_resources(tenant_id) do
  Resource
  |> where(tenant_id: ^tenant_id)
  |> Repo.all()
end

# In plug — extract tenant from conn and assign
defmodule MyAppWeb.Plugs.SetTenant do
  import Plug.Conn
  def init(opts), do: opts
  def call(conn, _opts) do
    tenant_id = get_req_header(conn, "x-tenant-id") |> List.first()
    assign(conn, :tenant_id, tenant_id)
  end
end

Always add a composite index on [:tenant_id, <resource_id or lookup field>].

Auth Plugs

API Key

defmodule MyAppWeb.Plugs.ApiKeyAuth do
  import Plug.Conn
  def init(opts), do: opts
  def call(conn, _opts) do
    with [key] <- get_req_header(conn, "x-api-key"),
         {:ok, account} <- Accounts.authenticate_api_key(key) do
      assign(conn, :current_account, account)
    else
      _ -> conn |> send_resp(401, "Unauthorized") |> halt()
    end
  end
end

Bearer Token

defmodule MyAppWeb.Plugs.BearerAuth do
  import Plug.Conn
  def init(opts), do: opts
  def call(conn, _opts) do
    with ["Bearer " <> token] <- get_req_header(conn, "authorization"),
         {:ok, claims} <- MyApp.Token.verify(token) do
      assign(conn, :current_user, claims)
    else
      _ -> conn |> send_resp(401, "Unauthorized") |> halt()
    end
  end
end

Router Structure

scope "/api/v1", MyAppWeb do
  pipe_through [:api, :authenticated]

  resources "/users", UserController, except: [:new, :edit]
  resources "/teams", TeamController, except: [:new, :edit] do
    resources "/members", MemberController, only: [:index, :create, :delete]
  end
end

Test Generation

See references/test-patterns.md for ExUnit, Mox, factory patterns.

Key rules:

  • Use async: true on all tests that don't share state.
  • Use Ecto.Adapters.SQL.Sandbox for DB isolation.
  • Factory module using ex_machina or hand-rolled build/1, insert/1.
  • Test contexts and controllers separately.
  • For controllers: test status codes, response body shape, and error cases.
  • Mock external services with Mox — define behaviours, set expectations in test.

Controller Test Template

defmodule MyAppWeb.UserControllerTest do
  use MyAppWeb.ConnCase, async: true

  import MyApp.Factory

  setup %{conn: conn} do
    user = insert(:user)
    conn = put_req_header(conn, "authorization", "Bearer #{token_for(user)}")
    {:ok, conn: conn, user: user}
  end

  describe "index" do
    test "lists users", %{conn: conn} do
      conn = get(conn, ~p"/api/v1/users")
      assert %{"data" => users} = json_response(conn, 200)
      assert is_list(users)
    end
  end

  describe "create" do
    test "returns 201 with valid params", %{conn: conn} do
      params = params_for(:user)
      conn = post(conn, ~p"/api/v1/users", user: params)
      assert %{"data" => %{"id" => _}} = json_response(conn, 201)
    end

    test "returns 422 with invalid params", %{conn: conn} do
      conn = post(conn, ~p"/api/v1/users", user: %{})
      assert json_response(conn, 422)["errors"] != %{}
    end
  end
end

JSON Renderer (Phoenix 1.7+)

defmodule MyAppWeb.UserJSON do
  def index(%{users: users}), do: %{data: for(u <- users, do: data(u))}
  def show(%{user: user}), do: %{data: data(user)}

  defp data(user) do
    %{
      id: user.id,
      email: user.email,
      inserted_at: user.inserted_at
    }
  end
end

Checklist Before Writing

  • Migrations use timestamps(type: :utc_datetime_usec)
  • Binary IDs configured if project uses UUIDs
  • Tenant scoping applied where needed
  • Auth plug wired in router pipeline
  • FallbackController handles {:error, changeset} and {:error, :not_found}
  • Tests cover 200, 201, 404, 422 status codes
  • Factory defined for each schema

Files

4 total
Select a file
Select a file to preview.

Comments

Loading comments…