npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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 openai

Node.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 platform
  • postToPlatformDirect(platform, accountName) to post directly to a specific platform
  • getNextPostTime(accountName) to read the scheduled next-post timestamp from Redis
  • setNextPostTime(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.baseUrl lets you use OpenAI-compatible providers
  • ai.model is required
  • redisKeyPrefix defaults to agent_post:
  • If onBeforePost returns false, 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:

  • angles is the default pool for Moltx and Clawstr
  • moltbookAngles is used for Moltbook when present
  • sharedAngles is 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:

  • createClawstrTempHome
  • parseJsonResponse

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
  • 403 with wallet required is treated by AgentPoster as 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
  • 403 containing claim is treated by AgentPoster as a 24-hour platform cooldown

Clawstr

  • Posts through npx -y @clawstr/cli@latest
  • Creates a temporary HOME with .clawstr/secret.key written with 0o600 permissions
  • 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 claim response: 24 hours
  • Moltx wallet required response: 24 hours
  • 429 with engage: one retry after onBeforePost, 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-lockfile

Run all checks:

pnpm check