Install
$ agentstack add skill-andrmaz-spec-driven-architecture-threads ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Threads and Input
Manages conversations, suggestions, voice input, and image attachments.
Quick Start
import { useTambo, useTamboThreadInput } from "@tambo-ai/react";
const { thread, messages, isIdle } = useTambo();
const { value, setValue, submit } = useTamboThreadInput();
await submit(); // sends current input value
Thread Management
Access and manage the current thread using useTambo() and useTamboThreadInput():
import {
useTambo,
useTamboThreadInput,
ComponentRenderer,
} from "@tambo-ai/react";
function Chat() {
const {
thread, // Current thread state
messages, // Messages with computed properties
isIdle, // True when not generating
isStreaming, // True when streaming response
isWaiting, // True when waiting for server
currentThreadId, // Active thread ID
switchThread, // Switch to different thread
startNewThread, // Create new thread, returns ID
cancelRun, // Cancel active generation
} = useTambo();
const {
value, // Current input value
setValue, // Update input
submit, // Send message
isPending, // Submission in progress
images, // Staged image files
addImage, // Add single image
removeImage, // Remove image by ID
} = useTamboThreadInput();
const handleSend = async () => {
await submit();
};
return (
{messages.map((msg) => (
{msg.content.map((block) => {
switch (block.type) {
case "text":
return {block.text};
case "component":
return (
);
case "tool_use":
return (
{block.statusMessage ?? `Running ${block.name}...`}
);
default:
return null;
}
})}
))}
setValue(e.target.value)} />
Send
);
}
Streaming State
| Property | Type | Description | | ------------- | --------- | --------------------------- | | isIdle | boolean | Not generating | | isWaiting | boolean | Waiting for server response | | isStreaming | boolean | Actively streaming response |
The streamingState object provides additional detail:
const { streamingState } = useTambo();
// streamingState.status: "idle" | "waiting" | "streaming"
// streamingState.runId: current run ID
// streamingState.error: { message, code } if error occurred
Content Block Types
Messages contain an array of content blocks. Handle each type:
| Type | Description | Key Fields | | ------------- | ---------------------- | ------------------------ | | text | Plain text | text | | component | AI-generated component | id, name, props | | tool_use | Tool invocation | id, name, input | | tool_result | Tool response | tool_use_id, content | | resource | MCP resource | uri, name, text |
Submit Options
const { submit } = useTamboThreadInput();
await submit({
threadId: "specific-thread", // Override target thread
toolChoice: "auto", // "auto" | "required" | "none" | { name: "toolName" }
maxTokens: 4096, // Max response tokens
systemPrompt: "Be helpful", // Override system prompt
});
Fetching a Thread by ID
To fetch a specific thread (e.g., for a detail view), use useTamboThread(threadId):
import { useTamboThread } from "@tambo-ai/react";
function ThreadView({ threadId }: { threadId: string }) {
const { data: thread, isLoading, isError } = useTamboThread(threadId);
if (isLoading) return ;
if (isError) return Failed to load thread;
return {thread.name};
}
This is a React Query hook - use it for read-only thread fetching, not for the active conversation.
Thread List
Manage multiple conversations:
import { useTambo, useTamboThreadList } from "@tambo-ai/react";
function ThreadSidebar() {
const { data, isLoading } = useTamboThreadList();
const { currentThreadId, switchThread, startNewThread } = useTambo();
if (isLoading) return ;
return (
startNewThread()}>New Thread
{data?.threads.map((t) => (
switchThread(t.id)}
className={currentThreadId === t.id ? "active" : ""}
>
{t.name || "Untitled"}
))}
);
}
Thread List Options
const { data } = useTamboThreadList({
userKey: "user_123", // Filter by user (defaults to provider's userKey)
limit: 20, // Max results
cursor: nextCursor, // Pagination cursor
});
// data.threads: TamboThread[]
// data.hasMore: boolean
// data.nextCursor: string
Suggestions
AI-generated follow-up suggestions after each assistant message:
import { useTamboSuggestions } from "@tambo-ai/react";
function Suggestions() {
const { suggestions, isLoading, accept, isAccepting } = useTamboSuggestions({
maxSuggestions: 3, // 1-10, default 3
autoGenerate: true, // Auto-generate after assistant message
});
if (isLoading) return ;
return (
{suggestions.map((s) => (
accept({ suggestion: s })}
disabled={isAccepting}
>
{s.title}
))}
);
}
Auto-Submit Suggestion
// Accept and immediately submit as a message
accept({ suggestion: s, shouldSubmit: true });
Manual Generation
const { generate, isGenerating } = useTamboSuggestions({
autoGenerate: false, // Disable auto-generation
});
generate()} disabled={isGenerating}>
Get suggestions
;
Voice Input
Speech-to-text transcription:
import { useTamboVoice } from "@tambo-ai/react";
function VoiceButton() {
const {
startRecording,
stopRecording,
isRecording,
isTranscribing,
transcript,
transcriptionError,
mediaAccessError,
} = useTamboVoice();
return (
{isRecording ? "Stop" : "Record"}
{isTranscribing && Transcribing...}
{transcript && {transcript}}
{transcriptionError && {transcriptionError}}
);
}
Voice Hook Returns
| Property | Type | Description | | -------------------- | ---------------- | --------------------------------- | | startRecording | () => void | Start recording, reset transcript | | stopRecording | () => void | Stop and start transcription | | isRecording | boolean | Currently recording | | isTranscribing | boolean | Processing audio | | transcript | string \| null | Transcribed text | | transcriptionError | string \| null | Transcription error | | mediaAccessError | string \| null | Mic access error |
Image Attachments
Images are managed via useTamboThreadInput():
import { useTamboThreadInput } from "@tambo-ai/react";
function ImageInput() {
const { images, addImage, addImages, removeImage, clearImages } =
useTamboThreadInput();
const handleFiles = async (files: FileList) => {
await addImages(Array.from(files));
};
return (
handleFiles(e.target.files!)}
/>
{images.map((img) => (
removeImage(img.id)}>Remove
))}
);
}
StagedImage Properties
| Property | Type | Description | | --------- | -------- | -------------------- | | id | string | Unique image ID | | name | string | File name | | dataUrl | string | Base64 data URL | | file | File | Original File object | | size | number | File size in bytes | | type | string | MIME type |
User Authentication
Enable per-user thread isolation:
import { TamboProvider } from "@tambo-ai/react";
function App() {
return (
);
}
For OAuth-based auth, use userToken instead:
function App() {
const userToken = useUserToken(); // From your auth provider
return (
);
}
Use userKey for simple user identification or userToken for OAuth JWT tokens. Don't use both.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: andrmaz
- Source: andrmaz/spec-driven-architecture
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.