The EFFECT node executor uses register_effect() to look up effects.
Added dog effect registration so DAG recipes can use effect: dog.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
After content negotiation fix, /cache/{hash} returns HTML for
browsers. Embedded <img> tags need /raw to get actual image data.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove output_name from publish form and endpoint
- Assets on L2 are now named by their content_hash
- All inputs, recipe, and output referenced by content_hash
- Simplified publish flow - no user input needed
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The /cache/{hash} endpoint now defaults to HTML for browsers. Raw
data was being returned for requests without explicit text/html in
Accept header (e.g., link clicks). JSON is only returned when
explicitly requested. Raw data is served only from /cache/{hash}/raw.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When cache metadata has type "recipe", return that instead of
auto-detecting (which returns "unknown" for YAML files). This
ensures L2 can properly register recipes as inputs.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Recipe detail page now shows the full YAML source
- Shows "View on L2" link if recipe is shared to L2
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The get_cache_manager() singleton wasn't initializing with Redis,
so workers couldn't see files uploaded via the API server.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Include artdag-client.tar.gz package
- Add /download/client route to serve the package
- Add "Download Client" link in nav bar
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The run_recipe endpoint was still using uuid.uuid4() instead of
compute_run_id(). Now it:
- Computes deterministic run_id from inputs + recipe
- Checks L1 cache before running
- Checks L2 and pulls from IPFS if needed
- Only runs Celery if output not found
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add run_cache table for fast run_id -> output lookup
- compute_run_id() computes deterministic run_id from inputs + recipe
- create_run checks L1 cache then L2 before running Celery
- If output exists on L2 but not L1, pulls from IPFS
- Saves run results to cache on completion
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove obsolete /ui, /ui/login, /ui/register, /ui/logout redirects
- Fix /ui/login links to use /login directly
- Add styled 404 page for HTML requests
- Add Web UI section to README documenting routes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Database: Use DISTINCT ON to deduplicate items by content_hash
- Database: Count unique content_hashes in count_user_items
- Server: Fix media card link from /ui/cache to /cache
- Server: Use /raw endpoint for image thumbnails
- Server: Add seen_hashes dedup in media list iteration
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Run detail page now shows "Published to L2" with link when already published
- Publish success message now includes "View on L2" link
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The cache_manager now uses Redis hashes for the content_index and
ipfs_cids mappings. This allows multiple uvicorn workers to share
state, so files added by one worker are immediately visible to all
others.
- Added redis_client parameter to L1CacheManager
- Index lookups check Redis first, then fall back to in-memory
- Index updates go to both Redis and JSON file (backup)
- Migrates existing JSON indexes to Redis on first load
- Re-enabled workers=4 in uvicorn
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
With multiple workers, each process has its own in-memory cache index.
Files added by one worker aren't visible to others, causing intermittent
404 errors.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Recipes have their own section under /recipes, so exclude them
from the media list by checking node_type == "recipe".
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When ui_publish_run publishes a run to L2, now properly records the
share in the local database so the UI can display the L2 badge and
published status.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Check Sec-Fetch-Mode: navigate header for direct browser access.
This ensures /cache/{hash} shows HTML detail page when navigating
directly, but still serves raw files for embedded <img>/<video> tags.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Run uvicorn with 4 workers to handle concurrent requests
- Add socket_timeout and socket_connect_timeout to Redis client (5s)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Make get_user_context_from_cookie and get_user_from_cookie async
since they call async get_verified_user_context. Update all callers.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add "Sync with L2" button on media page to fetch user's outbox
- Link asset names to L2 asset pages in publish status
- Add green "L2" badge to media list for published items
- Create /user/sync-l2 and /ui/sync-l2 endpoints
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add add_json() to ipfs_client for storing JSON data
- Update render_effect task to store provenance on IPFS
- Update execute_dag task to store DAG provenance on IPFS
- Add provenance_cid field to RunStatus model
- Extract provenance_cid from task results
Provenance is now immutable and content-addressed, enabling:
- Cross-L2 verification
- Bitcoin timestamping for dispute resolution
- Complete audit trail on IPFS
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Log timestamps for each operation in get_run and get_cached to
diagnose slowness:
- load_run from Redis
- Celery AsyncResult and task.ready()
- cache_file operations
- database queries for cache metadata
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Browsers get HTML detail page with video/image preview
- API clients with Accept: application/json get metadata JSON
- Other requests get raw file
- Add /cache/{content_hash}/raw for explicit file downloads
- Remove old /cache/{content_hash}/detail endpoint
- Update all /detail links to use clean /cache/{hash} URL
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Without importing artdag.nodes, the EFFECT executor was never
registered, causing "No executor for node type: EFFECT" errors.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use keyword arguments for Node constructor
- Pass inputs list to Node instead of calling non-existent add_edge
- Two-pass approach: create SOURCE nodes first, then resolve input
names to content-addressed IDs for dependent nodes
- Properly set output node using resolved ID
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When republishing/updating an asset on L2, now sends the IPFS CID
so L2 can update its record and pin the content.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace ipfshttpclient library with direct HTTP requests to IPFS API.
This fixes compatibility with newer Kubo versions (0.39.0+) which are
not supported by the outdated ipfshttpclient library.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Make cache_file() async and save ipfs_cid to cache_items table
- Update all call sites to use await
- Add create_cache_item call in upload endpoint
Fixes IPFS info not showing for uploaded files.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Enables full IPFS network participation - other nodes can
discover and fetch content from this node.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Escape {run_id} and {hash} as {{run_id}} and {{hash}} to
prevent NameError in f-string interpolation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
L1 now includes IPFS CID in publish requests so L2 can
pin content on its own IPFS node for federation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- IPFS_GATEWAY_URL env var for local gateway (e.g., https://ipfs.celery-artdag.rose-ash.com)
- Local gateway shown first with green button when configured
- Removed Pinata from public gateways list
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Cache detail page shows IPFS section with CID and links to
ipfs.io, dweb.link, Cloudflare, and Pinata gateways
- Media list cards show purple "IPFS" badge for items with CID
- JSON API response includes ipfs_cid field
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Convert static HOME_HTML to render_home_html() function that
dynamically shows user info with link to L2 profile when
authenticated, or login button when not logged in.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace all load_cache_meta/save_cache_meta calls with database functions
- Update get_user_cache_hashes to async, query both DB and legacy JSON
- Replace get_user_from_cookie with get_user_context_from_cookie throughout
- Update all endpoints to use UserContext (ctx) instead of plain username
- Update render_page calls to use ctx.actor_id
- Add high-level database helper functions:
- save_item_metadata, load_item_metadata, update_item_metadata
- save_l2_share, get_user_items, count_user_items
- Keep legacy JSON functions for backwards compatibility during migration
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- L1 never handles credentials - redirects to L2 for login/register
- L2 sets shared cookie (domain=.rose-ash.com) for cross-subdomain auth
- Display logged-in user as @user@server (ActivityPub format)
- Remove login/register form handling from L1
- Add L1_PUBLIC_URL env var for redirect callbacks
- Rename /ui/cache-list to /ui/media-list
- Update nav links to use clean URLs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Multi-user support for cache items:
- item_types now includes actor_id (@user@server format)
- l2_shares now includes actor_id
- Same cache item can be owned by multiple users with different types
- Deleting severs user's connection, not the actual file
- Cache files only removed when no users reference them
- Added has_remaining_references() and cleanup_orphaned_cache_item()
- Updated all CRUD functions to include actor_id parameter
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change navigation tab from "Cache" to "Media"
- Change /cache list route to /media
- Add Recipes link to home page navigation
- Add Login button to home page
- Update all active_tab="cache" to active_tab="media"
- Update "Back to cache" links to "Back to media"
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Removed duplicate /recipes route that was causing infinite redirect.
Now single route handles both HTML and JSON responses directly.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add PostgreSQL database for cache metadata storage with schema for
cache_items, item_types, pin_reasons, and l2_shares tables
- Add IPFS integration as durable backing store (local cache as hot storage)
- Add postgres and ipfs services to docker-compose.yml
- Update cache_manager to upload to IPFS and track CIDs
- Rename all config references to recipe throughout server.py
- Update API endpoints: /configs/* -> /recipes/*
- Update models: ConfigStatus -> RecipeStatus, ConfigRunRequest -> RecipeRunRequest
- Update UI tabs and pages to show Recipes instead of Configs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>