Skip to content

Content OS: content calendar, AI engine, chat assistant, MCP server - #1

Merged
djangify merged 8 commits into
mainfrom
content-os-build
Jul 30, 2026
Merged

Content OS: content calendar, AI engine, chat assistant, MCP server #1
djangify merged 8 commits into
mainfrom
content-os-build

Conversation

@djangify

Copy link
Copy Markdown
Owner

Turns Project Tracker into a Content OS — a content calendar with a provider-agnostic AI engine, a chat assistant, and an MCP server so the calendar can be driven from Claude Desktop. Single-user, single SQLite, no multi-tenancy. Built in five phases plus a Claude Desktop auto-connect, each committed separately.

What's included

  • Phase 1 — content_calendar: ContentItem (the spreadsheet columns) + Platform (M2M, seeded), calendar/board/table views, DRF, admin.
  • Phase 2 — ai_settings: AIProviderConfig with Fernet-encrypted keys, one ai_client adapter (generate + generate_with_tools) across OpenAI / Anthropic / Gemini, settings page with live "test connection".
  • Phase 3 — generation engine: ported VoiceProfile + distill_voice, PromptEnhancer, ContentTemplate/ContentTemplatePrompt; a Generate panel producing draft ContentItems.
  • Phase 4 — ai_assistant: shared tool set + agent loop, session-backed chat page.
  • Phase 5 — mcp_server: same tools over MCP stdio (FastMCP), runmcp command, connect-to-Claude doc.
  • Auto-connect: registers with Claude Desktop on first launch; packaging builds a second console ProjectTracker-mcp.exe.

Deliberate deviations from the plan

  • Gemini uses google-genai (plan's SDK is end-of-life); mcp pinned <2; added reschedule_content_item; chat UI uses vanilla fetch (no HTMX in codebase).

Cost model

Driving the calendar via Claude Desktop runs on the user's Claude subscription (no API key). The API key is only for the in-app Generate/Assistant and generate_draft/distill_voice.

Testing

100 tests pass. Packaged two-exe build verified; frozen ProjectTracker-mcp.exe completes an MCP stdio handshake with all 7 tools.

🤖 Generated with Claude Code

todiane and others added 8 commits July 30, 2026 11:10
Add a new content_calendar app that mirrors the content-planning
spreadsheet as a ContentItem model, with calendar/board/table views
cloned from the existing Task views.

- ContentItem: scheduled_date, pillar, content_type, topic, M2M to a
  small Platform model, hook/caption/CTA/hashtags/tags_links/audio,
  image_video_cover file, content_link, status + approval_status, and
  an optional FK to projects.Project.
- Platform seeded (TikTok/Instagram/Pinterest/Facebook/YouTube/WhatsApp)
  via data migration so it's populated on install.
- Calendar (month grid), board (grouped by approval status for review),
  and table views + UI create/edit/delete, all LoginRequiredMixin.
- DRF ContentItem/Platform viewsets, full admin CRUD, nav links.
- Tests for calendar render, board grouping, and approval updates.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add an ai_settings app so no AI feature is locked to one provider.

- AIProviderConfig: one row per provider (openai/anthropic/gemini),
  model_name, is_active (single active enforced on save). The API key is
  encrypted at rest with Fernet, keyed from SECRET_KEY (ai_settings/
  encryption.py) — never stored as plaintext.
- ai_client.py: one adapter with generate(system, user, temperature) and
  generate_with_tools(messages, tools, ...) returning a normalized
  ToolTurn, dispatching to OpenAI / Anthropic / Gemini via each native
  SDK. generate_with_tools is added now (used from Phase 4) so the
  interface is settled once.
- Settings page (login-gated) to add keys, choose the active provider,
  and a "test connection" button that calls generate() and shows the
  reply inline.
- Swap deprecated google-generativeai for the supported google-genai SDK.
- Tests for encryption round-trip, single-active, key preservation,
  settings save, and adapter error paths.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Port ai-marketing's content engine into content_calendar, rewired to the
Phase 2 provider-agnostic adapter.

- VoiceProfile (single-user singleton) + distill_voice(): one AI call turns
  pasted writing samples into a structured, reusable voice.
- PromptEnhancer: prompt layering adapted to return (system, user) for
  ai_client.generate() and to fold in the voice profile; ContentItem post
  types map onto the social prompt category.
- ContentTemplate / ContentTemplatePrompt: a named recipe of ordered,
  per-field prompts (hook/caption/CTA/hashtags) that land in one ContentItem.
- generate_content_item(): run a template or a free-text brief and create a
  draft ContentItem with approval_status="ready", using the active provider.
- Generate panel + Voice profile pages (login-gated), toolbar "Generate"
  button, admin for templates/voice. Tests mock the adapter (no live calls).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a chat assistant that acts on the calendar by calling tools.

- tools.py: the shared tool set (create_content_item, list_content_items,
  update_status, reschedule_content_item, generate_draft, distill_voice,
  get_calendar_month) as plain functions returning JSON-serializable dicts,
  plus normalized schemas and an execute_tool dispatcher. This is the single
  source of truth reused verbatim by the Phase 5 MCP server.
  (reschedule_content_item is added beyond the plan's six tools to satisfy
  the "move Tuesday's post to Thursday" acceptance criterion cleanly.)
- agent.py: run_turn() drives ai_client.generate_with_tools() in a loop —
  execute tool calls, feed results back, repeat until a plain-text reply,
  capped at MAX_STEPS.
- Chat page: session-backed transcript, vanilla fetch + Tailwind (matching
  the app's existing JS conventions — the codebase has no HTMX), with a
  thinking indicator, Enter-to-send, and clear-chat.
- Tests mock the adapter and cover every tool, the loop (incl. the cap),
  transcript filtering, and the chat views.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Expose the Phase 4 tool set to Claude Desktop / Cowork / Claude Code over
MCP's stdio transport — no new business logic, a second transport.

- mcp_server/server.py: FastMCP server with seven @mcp.tool() wrappers that
  call straight into ai_assistant.tools. Typed signatures give Claude clean
  input schemas. Runs standalone or imported after django.setup().
- runmcp management command launches it over stdio (stdout reserved for the
  protocol; status to stderr).
- DJANGO_ALLOW_ASYNC_UNSAFE is set in the server: FastMCP runs sync tools on
  its event loop, and this single-user, one-request-at-a-time local server
  can safely run SQLite queries there rather than threading every ORM call.
- mcp_server/README.md: connect-to-Claude doc — per-tool summary, one example
  prompt each, and the Desktop/Code config pointing at a local install.
- Pin mcp<2 (the 1.x line providing the @server.tool()/FastMCP API the plan
  targets; 2.0 dropped it). Verified end-to-end via a real stdio handshake
  (initialize + tools/list + live tool call). Tests cover registration and
  the wrappers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Keep CLAUDE_CODE_KICKOFF_PROMPT.md and CONTENT_OS_BUILD_PLAN.md on disk as
local reference but out of the repository.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make the MCP connection one-click for non-technical owners: on first run the
app registers itself in Claude Desktop's config, so they never hand-edit JSON.

- mcp_server/desktop_connect.py: safe, never-raising merge into
  claude_desktop_config.json. Preserves other keys/servers, refuses to clobber
  an unparseable file, idempotent. Dev points at `python manage.py runmcp`;
  packaged points at the sibling ProjectTracker-mcp.exe.
- desktop.py: first-run hook (once, via a marker file; retries only while
  Claude Desktop is absent) + a self-clearing "restart Claude Desktop" banner
  shown via a ?claude=connected URL flag.
- mcp_launcher.py: console entry point for the packaged MCP exe (stdio needs
  real stdin/stdout, which a windowed exe lacks) — also usable in dev.
- connect_claude management command for a manual/assisted turn-on.
- project_tracker.spec: FIX — it was missing all four new apps (packaged build
  would 500); add them + their templates, swap google.generativeai for
  google.genai, add mcp, and build a second console ProjectTracker-mcp.exe.
- Docs: Requirements (needs Claude Desktop) + free-vs-API-key sections in the
  MCP README and a friendly Section 8 in HOW-TO.
- Tests for the config merge (create/idempotent/preserve/no-claude/unreadable/
  dev+frozen entry). Verified in dev: connect_claude is idempotent and
  mcp_launcher speaks stdio with all 7 tools.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
collect_all("mcp") imported mcp.cli, which calls sys.exit(1) at import time
when the optional 'typer' dependency is absent, crashing the analyzer. Collect
only mcp.server/client/shared (plus mcp + mcp.types) and the package data;
the CLI isn't used. Verified: both ProjectTracker.exe and ProjectTracker-mcp.exe
build, and the packaged MCP exe completes an stdio handshake with all 7 tools.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@djangify
djangify merged commit 811158b into main Jul 30, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants