---
phase: 02-api-client-core-types
type: execute
---

<objective>
Create type-safe Pydantic models for n8n API responses and implement the first resource module (workflows) using the hub-and-spoke pattern.

Purpose: Ensure all API responses are validated and type-safe, with the workflow resource demonstrating the pattern for future resources.
Output: Working Pydantic models for core n8n types (Workflow, Execution, Project, User) and functional WorkflowsResource with list/get methods integrated into APIClient.
</objective>

<execution_context>
~/.claude/get-shit-done/workflows/execute-phase.md
./summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/02-api-client-core-types/02-RESEARCH.md
@.planning/phases/02-api-client-core-types/02-01-SUMMARY.md
@src/n8n_cli/client/core.py
@src/n8n_cli/client/exceptions.py
</context>

<tasks>

<task type="auto" tdd="true">
  <name>Task 1: Create Pydantic models for Workflow responses</name>
  <files>src/n8n_cli/client/models/__init__.py, src/n8n_cli/client/models/workflow.py, tests/test_models_workflow.py</files>
  <test-first>
Test: Workflow model validates and coerces n8n API responses
Cases:
- Valid workflow dict → Workflow object with all fields
- Field aliasing: createdAt → created_at, updatedAt → updated_at
- populate_by_name=True accepts both snake_case and camelCase
- Missing optional fields use defaults (tags=[], nodes=[], connections={})
- Invalid data raises ValidationError
  </test-first>
  <action>Create src/n8n_cli/client/models/ directory. In models/workflow.py, create Workflow(BaseModel) with fields: id (str), name (str), active (bool), created_at (datetime with alias="createdAt"), updated_at (datetime with alias="updatedAt"), tags (list[str] default []), nodes (list[dict] default []), connections (dict default {}), project_id (str | None with alias="projectId"). Add Config class with populate_by_name=True. Follow exact pattern from 02-RESEARCH.md Pydantic section. Export from models/__init__.py.</action>
  <verify>pytest tests/test_models_workflow.py passes, field aliasing works, validation catches invalid data</verify>
  <done>Workflow model validates all n8n workflow responses with proper field aliasing and type coercion</done>
</task>

<task type="auto" tdd="true">
  <name>Task 2: Create Pydantic models for Execution, Project, and User responses</name>
  <files>src/n8n_cli/client/models/execution.py, src/n8n_cli/client/models/project.py, src/n8n_cli/client/models/user.py, tests/test_models_other.py</files>
  <test-first>
Test: Execution, Project, User models validate API responses
Cases for Execution:
- Fields: id, workflow_id (alias workflowId), status, started_at (alias startedAt), finished_at (alias finishedAt, optional), mode, data (dict)
Cases for Project:
- Fields: id, name, type, created_at (alias createdAt), updated_at (alias updatedAt)
Cases for User:
- Fields: id, email, first_name (alias firstName, optional), last_name (alias lastName, optional), role
All use populate_by_name=True for field aliasing
  </test-first>
  <action>Create models/execution.py with Execution model (id, workflow_id, status, started_at, finished_at as Optional[datetime], mode, data as dict). Create models/project.py with Project model (id, name, type, created_at, updated_at). Create models/user.py with User model (id, email, first_name as Optional[str], last_name as Optional[str], role). All models use Field(alias=...) for camelCase API fields and Config with populate_by_name=True. Export all from models/__init__.py.</action>
  <verify>pytest tests/test_models_other.py passes, all models validate correctly with field aliasing</verify>
  <done>Execution, Project, User models complete with proper validation and field aliasing</done>
</task>

<task type="auto" tdd="true">
  <name>Task 3: Create WorkflowsResource with list/get methods and integrate into APIClient</name>
  <files>src/n8n_cli/client/resources/__init__.py, src/n8n_cli/client/resources/workflows.py, src/n8n_cli/client/core.py, tests/test_workflows_resource.py</files>
  <test-first>
Test: WorkflowsResource implements list() and get() methods
Cases for list():
- Returns list[Workflow] from /api/v1/workflows
- Accepts optional active filter parameter
- Handles pagination if present in API response
Cases for get():
- Returns single Workflow from /api/v1/workflows/{id}
- Raises NotFoundError for invalid ID (404)
Integration test:
- APIClient.workflows is WorkflowsResource instance
- client.workflows.list() works through hub
  </test-first>
  <action>Create src/n8n_cli/client/resources/ directory. In resources/workflows.py, create WorkflowsResource class. Constructor accepts httpx.Client. Implement list(active: bool | None = None) -> list[Workflow] that calls client.get("/api/v1/workflows", params=...), validates response, returns [Workflow.model_validate(w) for w in data]. Implement get(workflow_id: str) -> Workflow that calls client.get(f"/api/v1/workflows/{workflow_id}"), validates, returns Workflow. Add @retry decorator to both methods (same config as APIClient._request from Plan 1). Export from resources/__init__.py. Update core.py APIClient.__init__ to add self.workflows = WorkflowsResource(self._client). Update client/__init__.py exports.</action>
  <verify>pytest tests/test_workflows_resource.py passes with mocked httpx responses, integration test shows client.workflows.list() works</verify>
  <done>WorkflowsResource integrated into APIClient with working list() and get() methods using Pydantic validation</done>
</task>

</tasks>

<verification>
Before declaring plan complete:
- [ ] `pytest tests/test_models_workflow.py` passes all Workflow model tests
- [ ] `pytest tests/test_models_other.py` passes all other model tests
- [ ] `pytest tests/test_workflows_resource.py` passes all resource tests
- [ ] `pytest` runs all tests successfully (including Plan 1 tests)
- [ ] `uv run ruff check src/` passes with no errors
- [ ] `uv run mypy src/` passes with no type errors
- [ ] Test coverage remains above 80%
</verification>

<success_criteria>

- All tasks completed
- All verification checks pass
- Pydantic models validate all core n8n types
- Field aliasing works correctly (camelCase ↔ snake_case)
- WorkflowsResource demonstrates hub-and-spoke pattern
- APIClient.workflows property provides access to WorkflowsResource
- Phase 2 complete and ready for Phase 3 (Workflow Management commands)
</success_criteria>

<output>
After completion, create `.planning/phases/02-api-client-core-types/02-02-SUMMARY.md`:

# Phase 2 Plan 2: Pydantic Response Models and Resources Summary

**[Substantive one-liner - what shipped]**

## Accomplishments

- [Key outcome 1]
- [Key outcome 2]
- [Key outcome 3]

## Files Created/Modified

- `src/n8n_cli/client/models/__init__.py` - Description
- `src/n8n_cli/client/models/workflow.py` - Description
- `src/n8n_cli/client/models/execution.py` - Description
- `src/n8n_cli/client/models/project.py` - Description
- `src/n8n_cli/client/models/user.py` - Description
- `src/n8n_cli/client/resources/__init__.py` - Description
- `src/n8n_cli/client/resources/workflows.py` - Description
- `src/n8n_cli/client/core.py` - Description (updated with workflows property)
- `tests/test_models_workflow.py` - Description
- `tests/test_models_other.py` - Description
- `tests/test_workflows_resource.py` - Description

## Decisions Made

[Key decisions and rationale, or "None"]

## Issues Encountered

[Problems and resolutions, or "None"]

## Next Phase Readiness

Phase 2 (API Client & Core Types) complete. Ready for Phase 3 (Workflow Management commands).

**API Client established:**
- ✅ Hub-and-spoke architecture (APIClient hub with resource spokes)
- ✅ Custom exception hierarchy (401/404/429/5xx mapped)
- ✅ Connection pooling and retry logic (httpx.Client + tenacity)
- ✅ Type-safe Pydantic models (Workflow, Execution, Project, User)
- ✅ WorkflowsResource with list/get methods

**Next up:**
Phase 3 will implement workflow CLI commands (list, view, pull, push, etc.) using the API client.
</output>
