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

<objective>
Build the core API client infrastructure with connection pooling, custom exception hierarchy, and retry logic.

Purpose: Establish the foundation for all n8n API interactions with proper error handling and reliability patterns.
Output: Working APIClient hub class with exception hierarchy, retry decorators, and connection pooling ready for resource modules.
</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/01-foundation-configuration/01-01-SUMMARY.md
@.planning/phases/01-foundation-configuration/01-02-SUMMARY.md
@src/n8n_cli/config.py
@pyproject.toml
</context>

<tasks>

<task type="auto">
  <name>Task 1: Install tenacity dependency</name>
  <files>pyproject.toml, uv.lock</files>
  <action>Add tenacity>=9.0 to project.dependencies in pyproject.toml. Run `uv sync` to install and update lockfile. Verify installation with `uv pip list | grep tenacity`.</action>
  <verify>uv pip list shows tenacity 9.x installed, uv.lock updated</verify>
  <done>tenacity dependency added and locked</done>
</task>

<task type="auto" tdd="true">
  <name>Task 2: Create custom exception hierarchy for API errors</name>
  <files>src/n8n_cli/client/__init__.py, src/n8n_cli/client/exceptions.py, tests/test_exceptions.py</files>
  <test-first>
Test: Exception hierarchy with proper inheritance and HTTP status mapping
Cases:
- N8NAPIError is base exception
- AuthenticationError raised for 401
- NotFoundError raised for 404
- RateLimitError raised for 429
- ServerError raised for 5xx
- handle_response() maps status codes correctly
  </test-first>
  <action>Create src/n8n_cli/client/ directory. Implement exception hierarchy: N8NAPIError (base), AuthenticationError (401), NotFoundError (404), RateLimitError (429), ServerError (5xx), ValidationError (400). Create handle_response(response: httpx.Response) helper that raises appropriate exceptions based on status_code. Export all from client/__init__.py. Follow exact pattern from 02-RESEARCH.md exceptions section.</action>
  <verify>pytest tests/test_exceptions.py passes, all status codes mapped correctly</verify>
  <done>Exception hierarchy complete with handle_response() helper, all exceptions properly raised for respective status codes</done>
</task>

<task type="auto" tdd="true">
  <name>Task 3: Create base APIClient hub class with connection pooling</name>
  <files>src/n8n_cli/client/core.py, tests/test_client_core.py</files>
  <test-first>
Test: APIClient initialization, context manager, and request wrapper
Cases:
- APIClient.__init__() creates httpx.Client with base_url, headers, timeout
- Context manager (__enter__/__exit__) properly opens and closes client
- _request() method wraps httpx calls with retry decorator
- get()/post()/put()/delete() methods delegate to _request()
- Client reuses connection across multiple requests (connection pooling)
  </test-first>
  <action>Create src/n8n_cli/client/core.py. Implement APIClient class following hub-and-spoke pattern from 02-RESEARCH.md. Constructor accepts base_url, api_key, timeout (default 30.0). Creates httpx.Client with base_url, X-N8N-API-KEY header, timeout. Implement __enter__/__exit__ for context manager. Create _request(method, path, **kwargs) with @retry decorator (retry on httpx.HTTPError/ConnectionError, exponential backoff 2/4/8/10s, 3 attempts). Add convenience methods: get(), post(), put(), delete(). Import handle_response from exceptions and call in _request. DO NOT create resource properties yet (workflows, executions, etc.) - those come in Plan 2. Use typing.Self for __enter__ return type (Python 3.12 feature).</action>
  <verify>pytest tests/test_client_core.py passes, context manager works, retry logic tested with mocked failures</verify>
  <done>APIClient class complete with connection pooling, context manager, retry logic, and HTTP method helpers</done>
</task>

</tasks>

<verification>
Before declaring plan complete:
- [ ] `uv pip list | grep tenacity` shows tenacity installed
- [ ] `pytest tests/test_exceptions.py` passes all exception tests
- [ ] `pytest tests/test_client_core.py` passes all client tests
- [ ] `pytest` runs all tests successfully with no failures
- [ ] `uv run ruff check src/` passes with no errors
- [ ] `uv run mypy src/` passes with no type errors
</verification>

<success_criteria>

- All tasks completed
- All verification checks pass
- Exception hierarchy handles all HTTP error codes
- APIClient implements connection pooling correctly
- Retry logic configured with exponential backoff
- No errors or warnings introduced
</success_criteria>

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

# Phase 2 Plan 1: API Client Core Infrastructure Summary

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

## Accomplishments

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

## Files Created/Modified

- `src/n8n_cli/client/__init__.py` - Description
- `src/n8n_cli/client/exceptions.py` - Description
- `src/n8n_cli/client/core.py` - Description
- `tests/test_exceptions.py` - Description
- `tests/test_client_core.py` - Description
- `pyproject.toml` - Description

## Decisions Made

[Key decisions and rationale, or "None"]

## Issues Encountered

[Problems and resolutions, or "None"]

## Next Step

Ready for 02-02-PLAN.md (Pydantic Response Models and Resources)
</output>
