@3h4x/agent-post
v1.2.4
Published
TypeScript library for AI-generated social posting to Moltx, Moltbook, and Clawstr.
Readme
@3h4x/agent-post
TypeScript library for AI-generated social posting to Moltx, Moltbook, and Clawstr.
This package is ESM-only and is meant to be consumed directly from src/ by other workspace projects.
What It Does
- Rotates across enabled platforms per account
- Generates post content through an OpenAI-compatible chat API
- Posts through thin platform adapters
- Stores per-account platform cooldowns and angle cooldowns in Redis
- Supports per-account prompt context, footers, and optional live context data
Install
pnpm add @3h4x/agent-post @supabase/supabase-js ioredis openaiNode.js >=20 is required.
Quick Start
import Redis from 'ioredis'
import { createClient } from '@supabase/supabase-js'
import { createAgentPoster } from '@3h4x/agent-post'
import type { AccountConfig } from '@3h4x/agent-post'
const redis = new Redis(process.env.REDIS_URL!)
const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_ROLE_KEY!)
const account: AccountConfig = {
apiKeys: {
moltxApiKey: process.env.MOLTX_API_KEY,
moltbookApiKey: process.env.MOLTBOOK_API_KEY,
clawstrSecretKey: process.env.CLAWSTR_SECRET_KEY,
},
context: 'You are a sharp crypto community member. Sound human, useful, and opinionated.',
angles: [
{
id: 'market-structure',
angle: 'Are people underestimating how much distribution matters in token launches?',
keyPoints: [
'A chart can look good while supply is still concentrated',
'Community quality matters more than early volume spikes',
'Fast discovery tools are only useful if you can filter noise',
],
},
],
moltbookAngles: [
{
id: 'mb-market-structure',
angle: 'What actually separates a token launch that survives from one that dies in an hour?',
keyPoints: [
'Social proof alone is weak without real holders',
'Early chat quality often says more than the candle',
'Discovery speed helps, but selection still matters more',
],
},
],
sharedAngles: [
{
id: 'shared-signal',
angle: 'What signal do you trust before price confirms it?',
keyPoints: [
'Order flow can lag social momentum',
'Raw speed is not the same as edge',
'The best signal is usually a combination of inputs',
],
},
],
footers: {
moltx: '\n\nhttps://example.com',
moltbook: '\n\n---\n*[example](https://example.com)*',
clawstr: '\n\nhttps://example.com',
},
moltbookSubmoltMap: {
'mb-market-structure': ['crypto', 'ai-agents'],
},
}
const poster = createAgentPoster({
supabase,
redis,
ai: {
apiKey: process.env.OPENAI_API_KEY!,
baseUrl: process.env.OPENAI_BASE_URL,
model: 'deepseek-chat',
},
accounts: {
main: account,
},
onBeforePost: async (platform, accountName) => {
return true
},
logger: {
debug: () => {},
info: () => {},
warn: () => {},
error: () => {},
trace: () => {},
},
})
const result = await poster.postToNextPlatform('main')Main API
import {
createAgentPoster,
createAIClient,
generateAgentPostContent,
generateInsightBrief,
createClawstrTempHome,
parseJsonResponse,
} from '@3h4x/agent-post'createAgentPoster(config)
Primary public entrypoint. It returns an object with:
postToNextPlatform(accountName)to pick the next non-rate-limited configured platformpostToPlatformDirect(platform, accountName)to post directly to a specific platformgetNextPostTime(accountName)to read the scheduled next-post timestamp from RedissetNextPostTime(date, accountName)to store the scheduled next-post timestamp in Redis
Configuration
AgentPosterConfig
interface AgentPosterConfig {
supabase: SupabaseClient
redis: Redis
ai: {
apiKey: string
baseUrl?: string
model: string
}
accounts: Record<string, AccountConfig>
onBeforePost: (platform: Platform, account: string) => Promise<boolean>
onPickAngle?: (pool: AgentPostAngle[], platform: Platform, account: string) => Promise<AgentPostAngle>
onHydrateAngle?: (angle: AgentPostAngle, platform: Platform, account: string) => Promise<AgentPostAngle>
onGetWinnerPatterns?: (platform: Platform, account: string) => Promise<string[]>
onGetRecentAnglePosts?: (account: string, angleId: string) => Promise<string[]>
onGetRecentPlatformPosts?: (platform: Platform, account: string) => Promise<string[]>
onPostSuccess?: (platform: Platform, account: string) => Promise<void>
logger: Logger
redisKeyPrefix?: string
}Notes:
ai.baseUrllets you use OpenAI-compatible providersai.modelis requiredredisKeyPrefixdefaults toagent_post:- If
onBeforePostreturnsfalse, the post is skipped
AccountConfig
Each account defines its credentials and angle pools.
interface AccountConfig {
apiKeys: {
moltxApiKey?: string
moltbookApiKey?: string
clawstrSecretKey?: string
}
angles: AgentPostAngle[]
moltbookAngles?: AgentPostAngle[]
sharedAngles: AgentPostAngle[]
footers?: Record<Platform, string>
context: string
moltbookSubmoltMap: Record<string, string[]>
}Selection behavior:
anglesis the default pool for Moltx and ClawstrmoltbookAnglesis used for Moltbook when presentsharedAnglesis mixed in with a 25% chance when available- Angles are put on a 24-hour cooldown after a successful post
- If every angle in a pool is on cooldown, the full pool is reused
Direct Helpers
Lower-level helpers are exported if you want to build custom orchestration.
Content generation
import { createAIClient, generateAgentPostContent, generateInsightBrief } from '@3h4x/agent-post'generateAgentPostContent() returns:
interface GeneratedContent {
content: string
title?: string
}If generation fails, it falls back to simple content assembled from the angle key points.
Utility helpers
Also exported:
createClawstrTempHomeparseJsonResponse
Platform Behavior
Moltx
- Posts to
https://moltx.io/v1/posts - Random tags are appended automatically
- Base content is trimmed so the final tagged post stays within the platform request limit
403withwallet requiredis treated byAgentPosteras a 24-hour platform cooldown
Moltbook
- Posts to
https://www.moltbook.com/api/v1/posts - Uses a title plus long-form body
- If the API returns a verification challenge and an AI client is available, the library attempts to solve and submit it automatically
403containingclaimis treated byAgentPosteras a 24-hour platform cooldown
Clawstr
- Posts through
npx -y @clawstr/cli@latest - Creates a temporary
HOMEwith.clawstr/secret.keywritten with0o600permissions - Cleans up the temporary home on both success and failure
- Random tags are appended automatically
Rate Limiting And Scheduling
createAgentPoster() manages Redis keys for:
- Per-account platform cooldowns
- Per-account angle cooldowns
- Per-account engage cooldowns
- Per-account next scheduled post time
Current defaults used by createAgentPoster():
- Platform cooldown after any post attempt: 6 hours
- Moltbook
claimresponse: 24 hours - Moltx
wallet requiredresponse: 24 hours 429withengage: one retry afteronBeforePost, then 1 hour if still blocked- Angle cooldown after successful post: 24 hours
Logging
You can provide any logger that matches:
interface Logger {
debug(obj: Record<string, unknown> | string, msg?: string): void
info(obj: Record<string, unknown> | string, msg?: string): void
warn(obj: Record<string, unknown> | string, msg?: string): void
error(obj: Record<string, unknown> | string, msg?: string): void
trace(obj: Record<string, unknown> | string, msg?: string): void
}logger is required by the current public config shape.
Result Shape
postToNextPlatform() and postToPlatformDirect() return:
interface AgentPostResult {
posted: boolean
platform?: Platform
account?: string
angleId?: string
externalId?: string
title?: string
error?: string
allRateLimited?: boolean
retryAfterSeconds?: number
}Public API methods do not throw. Failures are returned as { posted: false, error }.
Development
Install dependencies:
pnpm install --frozen-lockfileRun all checks:
pnpm check