Claude-skill-registry conversation-state

Stateless conversation management with database-backed history, message persistence, and scalable architecture. Use when handling chat state, loading history, or building stateless APIs.

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/conversation-state" ~/.claude/skills/majiayu000-claude-skill-registry-conversation-state && rm -rf "$T"
manifest: skills/data/conversation-state/SKILL.md
source content

Stateless Conversation State Management

Load Conversation History

async def load_conversation_history(
    session: AsyncSession,
    user_id: str,
    conversation_id: int | None
) -> tuple[Conversation, list[dict]]:
    """Load or create conversation with message history."""
    if conversation_id:
        stmt = select(Conversation).where(
            Conversation.id == conversation_id,
            Conversation.user_id == user_id
        )
        result = await session.execute(stmt)
        conversation = result.scalar_one_or_none()
        if not conversation:
            raise HTTPException(status_code=404, detail="Conversation not found")
    else:
        conversation = Conversation(user_id=user_id)
        session.add(conversation)
        await session.commit()
        await session.refresh(conversation)
    
    # Load messages
    stmt = select(Message).where(
        Message.conversation_id == conversation.id
    ).order_by(Message.created_at)
    result = await session.execute(stmt)
    db_messages = result.scalars().all()
    
    messages = [{"role": msg.role, "content": msg.content} for msg in db_messages]
    return conversation, messages

Complete Stateless Flow

@app.post("/api/{user_id}/chat")
async def chat(
    user_id: str,
    request: ChatRequest,
    session: AsyncSession = Depends(get_db_session),
    current_user: str = Depends(verify_jwt)
):
    # 1. Load history from DB
    conversation, messages = await load_conversation_history(
        session, user_id, request.conversation_id
    )
    
    # 2. Save user message
    user_msg = Message(
        user_id=user_id,
        conversation_id=conversation.id,
        role="user",
        content=request.message
    )
    session.add(user_msg)
    await session.commit()
    
    # 3. Add to history array
    messages.append({"role": "user", "content": request.message})
    
    # 4. Run agent
    response, tool_calls = await run_agent(messages)
    
    # 5. Save assistant response
    assistant_msg = Message(
        user_id=user_id,
        conversation_id=conversation.id,
        role="assistant",
        content=response
    )
    session.add(assistant_msg)
    await session.commit()
    
    # 6. Return (server holds NO state)
    return ChatResponse(
        conversation_id=conversation.id,
        response=response,
        tool_calls=tool_calls
    )

Benefits

  • Horizontal scalability (any server handles any request)
  • Resilience (server restart doesn't lose conversations)
  • Testability (each request independent)
  • No sticky sessions needed