Spring Intelligence API
Spring Intelligence is Flow's AI-powered content research and generation engine. It automates signal discovery, relevance scoring, and content drafting based on your knowledge base and stance.
Overview
Spring Intelligence helps you:
- Discover signals - Monitor RSS feeds, URLs, and semantic searches
- Score relevance - AI-powered filtering against your knowledge base
- Generate drafts - Platform-specific content from high-relevance signals
- Track performance - Analytics on acceptance rate and edit distance
Architecture
Signal Sources → Ingestion → Relevance Engine → Draft Generation → Review Queue
↓ ↓ ↓ ↓ ↓
RSS/URL Extract Content LLM Scoring Knowledge+Stance Human Review
Authentication
All endpoints require authentication:
Authorization: Bearer flow_sk_live_abc123...
Knowledge Base
Your knowledge base defines who you are and what you build. It's used for:
- Relevance scoring (is this signal relevant to us?)
- Draft generation (what opinions should we inject?)
Get Knowledge Base
GET /api/spring/knowledge
Response (Not Configured)
{
"configured": false,
"knowledge": null,
"stance": null
}
Response (Configured)
{
"configured": true,
"knowledge": {
"productName": "Flow Social",
"productTagline": "The zen social media scheduler",
"productDescription": "A calm, beautiful platform for scheduling social posts",
"productFeatures": ["AI content generation", "Multi-platform posting"],
"valuePropositions": ["Save time", "Post consistently"],
"targetAudience": "Content creators and founders",
"idealCustomerProfile": "Solo founders with limited time",
"techStack": ["Cloudflare Workers", "React", "TypeScript"]
},
"stance": {
"hotTakes": ["Serverless is the future", "Quality over quantity"],
"loves": ["Developer experience", "Clean APIs"],
"hates": ["Bloated software", "Complexity for its own sake"],
"contrarianViews": ["Social media should be zen, not stressful"],
"toneKeywords": ["professional", "friendly", "technical"]
}
}
Create/Update Knowledge Base
PUT /api/spring/knowledge
Content-Type: application/json
{
"productName": "My Product",
"productTagline": "Best product ever",
"productDescription": "A detailed description",
"productFeatures": ["Feature 1", "Feature 2"],
"valuePropositions": ["Value 1", "Value 2"],
"targetAudience": "Developers",
"idealCustomerProfile": "Senior engineers at startups",
"techStack": ["Node.js", "React"]
}
Update Stance Only
PATCH /api/spring/knowledge/stance
Content-Type: application/json
{
"hotTakes": ["Hot take 1", "Hot take 2"],
"loves": ["Thing we love"],
"hates": ["Thing we hate"],
"contrarianViews": ["Contrarian view"],
"toneKeywords": ["professional", "witty"]
}
Signal Sources
Configure where Spring looks for content to react to.
List Sources
GET /api/spring/sources
Response
{
"sources": [
{
"id": "src_abc123",
"type": "rss",
"label": "Hacker News",
"config": { "url": "https://news.ycombinator.com/rss" },
"frequency": "hourly",
"isActive": true,
"lastChecked": 1706000000000
},
{
"id": "src_def456",
"type": "semantic_search",
"label": "Industry Pain Points",
"config": { "query": "social media scheduling problems" },
"frequency": "daily",
"isActive": true
}
],
"count": 2
}
Add Source
POST /api/spring/sources
Content-Type: application/json
{
"type": "rss",
"label": "TechCrunch",
"config": { "url": "https://techcrunch.com/feed/" },
"frequency": "hourly"
}
Source Types
| Type | Config | Description |
|---|---|---|
rss | { url: string } | RSS/Atom feed URL |
url | { url: string } | Direct webpage URL |
semantic_search | { query: string } | Semantic search query |
Frequencies
hourly- Check every hourdaily- Check once per day (midnight UTC)weekly- Check once per week (Sunday midnight UTC)
Update Source
PATCH /api/spring/sources/:id
Content-Type: application/json
{
"label": "Updated Label",
"frequency": "daily",
"isActive": false
}
Delete Source
DELETE /api/spring/sources/:id
Processed Signals
Signals are content items discovered from your sources and scored for relevance.
List Signals
GET /api/spring/signals
GET /api/spring/signals?status=relevant&limit=20
Query Parameters
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by status: pending, relevant, discarded, used, expired |
limit | integer | Max signals to return (default: 50) |
Response
{
"signals": [
{
"id": "sig_abc123",
"url": "https://example.com/article",
"title": "Industry News: Major Announcement",
"contentSummary": "Summary of the article...",
"relevanceScore": 85,
"relevanceReasoning": "Directly impacts target audience pain points",
"triggerType": "market_shift",
"status": "relevant",
"discoveredAt": 1706000000000
}
],
"count": 1
}
Relevance Scores
| Score Range | Meaning | Action |
|---|---|---|
| 0-50 | Noise | Auto-discarded |
| 51-79 | Weak signal | Logged but not drafted |
| 80-100 | High signal | Proceed to drafting |
Trigger Types
| Type | Description |
|---|---|
news | General industry news |
competitor | Competitor activity or announcement |
market_shift | Market trend or change |
user_complaint | User pain point or problem |
validation | Validates your approach/thesis |
Submit URL for Processing
Manually submit a URL to be processed.
POST /api/spring/signals/submit
Content-Type: application/json
{
"url": "https://example.com/interesting-article",
"title": "Optional title"
}
Response
{
"success": true,
"signalId": "sig_xyz789",
"message": "URL submitted for processing. It will be scored shortly."
}
Update Signal Status
PATCH /api/spring/signals/:id/status
Content-Type: application/json
{
"status": "used"
}
Draft Generation
Generate platform-specific content from a signal.
Generate Draft
POST /api/spring/signals/:id/draft
Response
{
"success": true,
"signal": {
"id": "sig_abc123",
"title": "Industry News: Major Announcement",
"url": "https://example.com/article",
"relevanceScore": 85,
"triggerType": "market_shift"
},
"drafts": {
"twitter": "The market is shifting toward [topic]. This is exactly why we built [product]. Here's my take: [opinion based on stance]. What do you think?",
"linkedin": "I've been watching [topic] closely for the past few months...\n\n[Longer form content with paragraphs]\n\nWhat's your perspective on this shift?"
},
"quality": {
"score": 0.85,
"reasoning": "Strong connection to knowledge base and clear stance integration"
}
}
Requirements
- Knowledge base must be configured
ANTHROPIC_API_KEYenvironment variable must be set
Analytics
Track your Spring Intelligence performance.
Get Analytics
GET /api/spring/analytics
GET /api/spring/analytics?days=30
Response
{
"period": {
"start": 1703000000000,
"end": 1706000000000,
"days": 30
},
"signals": {
"discovered": 150,
"relevant": 45,
"weak": 60,
"discarded": 45,
"used": 20
},
"drafts": {
"generated": 45,
"approved": 18,
"rejected": 12,
"edited": 15
},
"quality": {
"avgRelevanceScore": 72,
"avgEditDistance": 15,
"acceptanceRate": 40.0
},
"dailyBreakdown": [
{ "date": "2024-01-20", "signalsDiscovered": 5, "draftsGenerated": 2, "draftsApproved": 1 },
{ "date": "2024-01-19", "signalsDiscovered": 8, "draftsGenerated": 3, "draftsApproved": 2 }
]
}
Track Events
Track draft approval/rejection for analytics.
POST /api/spring/analytics/track
Content-Type: application/json
{
"eventType": "draft_approved",
"signalId": "sig_abc123",
"editDistance": 12
}
Event Types
| Event | Description |
|---|---|
draft_generated | Draft was generated from signal |
draft_approved | Draft was approved (include editDistance) |
draft_rejected | Draft was rejected (include reason) |
post_published | Content was published (include platform) |
Check Content Drift
Detect if you're repeating topics too frequently.
GET /api/spring/analytics/drift?topic=serverless&days=7
Response
{
"hasDrift": true,
"similarTopics": [
"Serverless computing trends",
"Why serverless matters"
],
"lastMentioned": "2024-01-18T10:00:00Z"
}
Cron Worker
Spring Intelligence includes a scheduled worker for automatic signal ingestion.
Deployment
Deploy the signal ingestor as a separate Cloudflare Worker:
wrangler deploy -c wrangler.worker.toml
Schedule
By default, the worker runs hourly to:
- Fetch sources due for checking
- Ingest content from RSS feeds and URLs
- Score relevance against your knowledge base
- Store high-relevance signals
SDK Examples
TypeScript SDK
import { Flow } from '@flowdev/sdk';
const flow = new Flow('flow_sk_live_...');
// Setup knowledge base
await flow.spring.updateKnowledge({
productName: 'My Product',
productFeatures: ['Feature 1', 'Feature 2'],
});
// Add signal source
await flow.spring.addSource({
type: 'rss',
label: 'Tech News',
config: { url: 'https://example.com/feed.xml' },
frequency: 'hourly',
});
// Get relevant signals
const { signals } = await flow.spring.getSignals({ status: 'relevant' });
// Generate draft from signal
const { drafts } = await flow.spring.generateDraft(signals[0].id);
console.log('Twitter:', drafts.twitter);
console.log('LinkedIn:', drafts.linkedin);
// Track approval
await flow.spring.trackEvent({
eventType: 'draft_approved',
signalId: signals[0].id,
editDistance: 10,
});
Python SDK
from flow_sdk import Flow
flow = Flow('flow_sk_live_...')
# Setup knowledge
flow.spring.update_knowledge(
product_name='My Product',
product_features=['Feature 1', 'Feature 2']
)
# Get signals
signals = flow.spring.get_signals(status='relevant')
# Generate draft
drafts = flow.spring.generate_draft(signals[0]['id'])
print(f"Twitter: {drafts['twitter']}")
Best Practices
Knowledge Base
- Be specific about your target audience and ICP
- Include your tech stack for technical relevance matching
- Define clear hot takes for opinionated content generation
Signal Sources
- Start with 3-5 high-quality sources rather than many mediocre ones
- Use semantic search for pain point discovery
- Monitor competitor changelogs for reactive content opportunities
Content Quality
- Review and edit AI-generated drafts before publishing
- Track edit distance to improve generation over time
- Check for content drift to avoid repetitive topics
Performance Targets
| Metric | Target | Description |
|---|---|---|
| Acceptance Rate | >30% | % of drafts approved for publishing |
| Edit Distance | <20% | % of characters changed in approved drafts |
| Relevance Score | >75 avg | Average score of processed signals |
Error Codes
| Status | Error | Description |
|---|---|---|
| 400 | Knowledge base not configured | Setup knowledge before generating drafts |
| 400 | URL already processed | Signal deduplication in effect |
| 400 | Invalid source type | Must be rss, url, or semantic_search |
| 500 | AI generation not configured | ANTHROPIC_API_KEY not set |
| 500 | Failed to generate drafts | LLM API error |