# metalworks

> Open-source Python library for marketing research and Reddit engagement.
> Produces demand reports from real Reddit conversations and provides the
> OAuth / search / compliance primitives to act on them. MIT licensed and
> fully composable. Pre-release (0.0.1): APIs below 1.0 are unstable
> except `metalworks.contract` models and the MCP tool contracts.

Core is dependency-light (pydantic, httpx, typer, rich). Provider SDKs live
behind extras and are lazy-imported; a bare `import metalworks` pulls in no
provider modules. Install the pipeline + one provider:
`pip install "metalworks[research,openai]"` (or `[research,anthropic]`,
`[research,google]`). One chat key is enough — embeddings resolve from a Google
or OpenAI key when present, else fall back to a bundled local model (`fastembed`,
no key). So Anthropic/OpenRouter/local chat all work standalone.

## Entry points

- `from metalworks import Metalworks` — the high-level facade and the one entry
  point most users need. `Metalworks()` resolves a provider from your env keys
  (or pass `model="provider/model"`).
  - `.research(question, subreddits=[...])` -> `DemandReport`.
  - `.plan(prompt)` -> `ResearchBrief` (walks the D1-D8 planner).
  - `.reddit.{search,subreddit,comments,rules,inbox,post}` — Reddit surfaces
    (reads are zero-key; `.post` is gated by the compliance check and audited).
  - `.discovery.{run,filter,generate}` — the discovery loop and its building blocks.
- `metalworks.research.run_research(deps, *, brief)` -> `DemandReport`. The
  research vertical underneath the facade. Quotes are exact-matched to stored
  Reddit comments; web findings carry source URLs from grounding metadata, never
  model prose.
- Seven functions on a finished `DemandReport`, each linking its output back to the
  report's real quotes: `build_positioning_brief`, `run_competitor_map`,
  `decide_surface` / `build_ux_skeleton`, `build_marketing_site` /
  `render_site_html`, `build_spec_from_report` / `scaffold` (a `BuildSpec` + a
  project scaffold for your own coding agent; metalworks writes no product code),
  `build_launch_assets` / `plan_channels`, `content_plan_from_report`
  (deterministic, zero-key). All on the `Metalworks` facade
  (`mw.positioning/competitors/surface/ux/site/build_spec/scaffold/launch/channel_plan/content_plan`),
  the CLI `metalworks research position|competitor-map|surface|site|launch|content-plan`
  + `metalworks build init`, and the matching synchronous MCP tools.
- `metalworks.discovery`: `run_discovery`, plus the public `filter_post` and
  `draft_reply` building blocks.
- `metalworks.reddit`: `RedditSearch`, `RedditOAuth`, `RedditMetrics`,
  `fetch_subreddit_intel`, `RateLimiter`, and `heuristic_check` /
  `heuristic_check_post` (a deterministic, zero-key compliance gate).
- `metalworks.contract`: the stable Pydantic wire models.
- `metalworks.testing`: public conformance suites for third-party adapters and
  repo backends.

Model refs: `provider:id` or `provider/model`. Point at any OpenAI-compatible
endpoint (OpenRouter, vLLM, LM Studio, local) with `OpenAIChatModel(base_url=...,
api_key_env=...)`. Set a cheap triage model with `Metalworks(model=..., fast_model=...)`.

## Protocols (the seam everything speaks through)

- `ChatModel` (`complete_text`, `complete_structured`), `GroundedChatModel`
  (adds `complete_grounded` with char-offset provenance).
- `SearchProvider`, `EmbeddingProvider` (with a hard index-identity guard).
- Typed repos: `CorpusRepo`, `BriefRepo`, `RunRepo`, `AccountRepo`,
  `OpportunityRepo`, `InboxRepo`. Backends shipped in core: `MemoryStores`,
  `SqliteStores`; hosted backends (Postgres/PostgREST) are a downstream custom
  store.

## Usage policy

For authentic, disclosed engagement only. No fake personas, no invented account
backstories, no vote manipulation, no coordinated inauthentic behavior. Tooling
that fabricates account backstories is deliberately not part of metalworks. See
USAGE_POLICY.md.
