An unofficial TypeScript port of CrewAI — build multi-agent workflows with agents, tasks, and crews using a native TypeScript API.
The core package is intentionally small: it contains the execution core, shared contracts, tools, checkpoints, and provider registration hooks. Native providers and optional features such as RAG/PDF parsing, MCP, A2A/A2UI, and Flow live in separate packages so Lambda and serverless users can install only what they need. Packages ship both ESM and CommonJS builds with full type declarations, and provide Python-style snake_case aliases for common async entry points to ease migration from the Python library.
Unofficial project. This is a community port and is not affiliated with, endorsed by, or maintained by crewAI, Inc. "CrewAI" belongs to its respective owner. The original CrewAI is MIT-licensed (Copyright © crewAI, Inc.); this port retains that notice — see License.
This repository is a pnpm workspace. The root README.md documents the public
package; per-package READMEs live next to each package's package.json.
| Package | Description | Path |
|---|---|---|
@crewai-ts/core |
Lightweight execution core: agents, tasks, crews, tools, checkpoints, provider contracts, and shared hooks. | packages/core/ |
@crewai-ts/gemini |
Gemini native provider and model catalog. | packages/gemini/ |
@crewai-ts/openai |
OpenAI and OpenAI-compatible native providers. | packages/openai/ |
@crewai-ts/anthropic |
Anthropic native provider. | packages/anthropic/ |
@crewai-ts/bedrock |
AWS Bedrock native provider. | packages/bedrock/ |
@crewai-ts/azure |
Azure OpenAI native provider. | packages/azure/ |
@crewai-ts/snowflake |
Snowflake Cortex native provider. | packages/snowflake/ |
@crewai-ts/mcp |
MCP tool integration and SDK-backed transports. | packages/mcp/ |
@crewai-ts/rag |
Knowledge, Memory, RAG, file ingestion, and PDF text extraction. | packages/rag/ |
@crewai-ts/a2a |
A2A and A2UI protocol support. | packages/a2a/ |
@crewai-ts/flow |
Flow orchestration, persistence, visualization, and Flow DSL compatibility paths. | packages/flow/ |
@crewai-ts/nestjs |
NestJS DI integration for @crewai-ts/core (DI tokens, modules, dynamic modules). |
packages/nestjs/ |
@crewai-ts/cli |
Command-line tool for scaffolding and inspecting CrewAI-style projects. | packages/cli/ |
pnpm add @crewai-ts/core # or npm install @crewai-ts/core # or yarn add @crewai-ts/core
Install provider and feature packages explicitly:
# Gemini-only install path pnpm add @crewai-ts/core @crewai-ts/gemini # Optional feature packages pnpm add @crewai-ts/rag @crewai-ts/mcp @crewai-ts/a2a @crewai-ts/flow
This package split is a breaking package-boundary change. See
docs/PACKAGE_SPLIT_MIGRATION.md for old
@crewai-ts/core import replacements.
This repo is a pnpm workspace (Node >= 22, pnpm 9.15.0). All work happens from
the repository root; per-package scripts are fanned out with pnpm -r.
# Install every workspace package (root + packages/*) pnpm install # Run a script in every package (build, lint, test, check, ...) pnpm -r build pnpm -r lint pnpm -r test pnpm -r check # Run a script in a single package pnpm -F @crewai-ts/core test pnpm -F @crewai-ts/nestjs build pnpm -F @crewai-ts/cli lint # Add a dependency to a single package pnpm -F @crewai-ts/nestjs add reflect-metadata
Workspace layout:
packages/
core/ # @crewai-ts/core
gemini/ # @crewai-ts/gemini
openai/ # @crewai-ts/openai
anthropic/ # @crewai-ts/anthropic
bedrock/ # @crewai-ts/bedrock
azure/ # @crewai-ts/azure
snowflake/ # @crewai-ts/snowflake
mcp/ # @crewai-ts/mcp
rag/ # @crewai-ts/rag
a2a/ # @crewai-ts/a2a
flow/ # @crewai-ts/flow
nestjs/ # @crewai-ts/nestjs
cli/ # @crewai-ts/cli
Cross-package references use the workspace:* protocol — for example
@crewai-ts/nestjs declares "@crewai-ts/core": "workspace:*" in its
peerDependencies, which pnpm resolves to the local packages/core/
checkout during development.
- Node.js >= 22 (the build targets
node22and usesnode:sqlitefor the SQLite checkpoint provider) - Works in both ESM (
import) and CommonJS (require) projects — types are resolved per module system.
// ESM import { Agent, Crew, Task } from "@crewai-ts/core";
// CommonJS const { Agent, Crew, Task } = require("@crewai-ts/core");
@crewai-ts/core is no longer an umbrella package for every provider and optional
feature. Import providers and feature APIs from their owning packages:
| Old surface | New package |
|---|---|
GeminiCompletion, Gemini model constants |
@crewai-ts/gemini |
OpenAICompletion, OpenAI-compatible providers |
@crewai-ts/openai |
AnthropicCompletion |
@crewai-ts/anthropic |
BedrockCompletion |
@crewai-ts/bedrock |
AzureCompletion |
@crewai-ts/azure |
SnowflakeCompletion |
@crewai-ts/snowflake |
| MCP clients and native tools | @crewai-ts/mcp |
| Memory, Knowledge, RAG, PDF parsing | @crewai-ts/rag |
| A2A and A2UI | @crewai-ts/a2a |
| Flow APIs and Flow DSL paths | @crewai-ts/flow |
The core package has no direct install dependencies. Optional dependencies are
owned by their feature packages: @crewai-ts/rag owns pdf-parse,
@crewai-ts/mcp owns @modelcontextprotocol/sdk, and @crewai-ts/flow owns
yaml.
See docs/PACKAGE_SPLIT_MIGRATION.md for a
complete migration guide.
import { Agent, Crew, Process, Task, agent, crew, task } from "@crewai-ts/core"; class ResearchCrew { @agent researcher() { return new Agent({ role: "Researcher", goal: "Find facts", backstory: "Careful analyst", llm: (messages) => `result: ${messages.at(-1)?.content ?? ""}`, }); } @task researchTask() { return new Task({ description: "Research {topic}", expectedOutput: "A concise brief", agent: this.researcher(), }); } @crew crew() { return new Crew({ process: Process.sequential }); } } const result = await new ResearchCrew().crew().kickoff({ inputs: { topic: "CrewAI" }, }); const batchResults = await new ResearchCrew().crew().kickoffForEach({ inputs: [{ topic: "CrewAI" }, { topic: "TypeScript" }], });
Decorators store only library-private metadata. They do not use
reflect-metadata, parameter decorators, or Nest metadata, so Nest applications should consume this package as a normal TypeScript library and keep Nest DI separate.
CrewAI Python-style snake_case aliases are available for common async entry points,
including kickoff_async, kickoff_for_each, kickoff_for_each_async,
akickoff_for_each, resume_async, from_pending, and from_state.
- Features
- Streaming
- LiteAgent
- Hooks
- Security
- Checkpoints
- Tools
- LLM providers
- Breaking package split
- Agent planning
- Flows
- Task output files
- Task input files
- Conditional tasks
- Human input
- Crew planning
- Memory
- Knowledge
- YAML-backed project config
- Development
- License
Agents, tasks, and crews
Agent,Task,ConditionalTask,Crew,TaskOutput, andCrewOutputLiteAgentandLiteAgentOutputcompatibility layer for direct agent execution- sequential
Crew.kickoff({ inputs })and sequential process async task scheduling, including sync barriers and CrewAI-style async validation - hierarchical process with manager agent / manager LLM validation and coworker delegation tools
- sequential
allowDelegationagents with coworker delegate / question tools kickoffForEach/kickoffForEachAsyncbatch execution with aggregate usage metrics- crew
replay(taskRef, inputs?)from a task id, name, index, or task object - crew-level planning that injects per-task execution plans before kickoff
- CrewAI-style default task context aggregation from previous task outputs
Decorators and project config
- standard TS decorators:
@agent,@task,@crew,@beforeKickoff,@afterKickoff,@outputJson,@outputPydantic,@start,@listen,@router CrewProjectYAML / object config loading foragentsConfigandtasksConfig
Agent execution controls
- iterative agent tool-use loop with
maxIterandresultAsAnswersupport - agent
maxRetryLimitretries around task execution failures - agent
maxExecutionTimetimeout enforcement for task execution - agent and crew
maxRpmthrottling for LLM calls - agent
useSystemPromptcontrol for models that do not accept system-role messages - agent
systemTemplate,promptTemplate, andresponseTemplateprompt rendering - agent
injectDate/dateFormatprompt injection - callable agent
guardrailwith retry-limit enforcement - agent-level
PlanningConfig,planning, and legacyreasoningcompatibility - deprecated CrewAI agent compatibility fields:
allowCodeExecution,codeExecutionMode,respectContextWindow,multimodal
Tasks
- task
outputFilewriting with input interpolation and safe path validation - task
inputFiles/input_filestext file prompt injection, plus an automaticread_filetool for named task, crew, and agent input files - task
outputConverter/converter_clshooks for structured output conversion - structured task interpolation for strings, numbers, booleans, arrays, objects, and
null - single or ordered multiple task
guardrailswith retry support - task
humanInputfeedback loops with injectable providers - task execution counters:
usedTools,toolsErrors,delegations,promptContext,processedByAgents - task
allowCrewaiTriggerContextsupport forcrewai_trigger_payloadkickoff inputs ConditionalTaskskip logic based on the previous task output
Tools
BaseTool/StructuredToolwith argument validation, usage limits, tool-call execution, and task-level tool overrides- tool result caching with
cacheFunctionand shareableInMemoryToolCache - crew
cache: falsecontrol for disabling library tool result caching
LLM providers
- function or object LLM providers with tool-call options, string model registry, and token usage aggregation
- native provider implementations live in explicit packages such as
@crewai-ts/gemini
Flows
- available from
@crewai-ts/flow:Flow, standard TS@start,@listen,@router,or_,and_,ask()input providers, and@humanFeedback - basic
stream: truecrew output from core, plus flow streaming from@crewai-ts/flow
Events and hooks
- typed
crewaiEventBuslifecycle events for crew kickoff, task execution, tool usage, and failures - agent and crew
stepCallbackhooks for tool / final agent steps - crew-level
taskCallbackhooks after task callbacks, with duplicate callback suppression - global before / after LLM and tool call hooks
Memory and knowledge
- available from
@crewai-ts/rag:Memory/MemoryScopewith recall / save tools injected into crews when memory is enabled - available from
@crewai-ts/rag:Knowledgesources (StringKnowledgeSource,TextFileKnowledgeSource,JSONKnowledgeSource,CSVKnowledgeSource) with agent and crew context injection
State, security, and checkpoints
- security
Fingerprint/SecurityConfigon agents, crews, and tasks - checkpoint
CheckpointConfig, filesystemJsonProvider, and SQLiteSqliteProvider - state
EventRecord/EventNodegraph for event relationship tracking - state
RuntimeStatecheckpoint serialization, restore, lineage, and fork helpers - crew
outputLogFiletask execution logs in text or JSON files - crew
executionLogsandtaskExecutionOutputJsonFilesfor per-task audit records
Set stream: true on a crew or flow to receive a streaming output wrapper from
kickoff(). The current TypeScript port exposes the final output as an async
stream chunk and makes the complete result available after iteration.
import { CrewStreamingOutput } from "@crewai-ts/core"; const streaming = await crew.kickoff() as unknown as CrewStreamingOutput; for await (const chunk of streaming) { console.log(chunk.content); } console.log(streaming.result.raw);
LiteAgent mirrors CrewAI's deprecated lightweight direct-execution API while
reusing the main Agent runtime internally. It returns LiteAgentOutput, keeps
the executed messages, exposes usage metrics, and supports the common
snake_case aliases.
import { LiteAgent } from "@crewai-ts/core"; const agent = new LiteAgent({ role: "Research Assistant", goal: "Answer quickly", backstory: "A concise research helper", llm: (messages) => `answer: ${messages.at(-1)?.content ?? ""}`, }); const output = await agent.kickoff_async("What is CrewAI?"); console.log(output.raw);
Register global hooks to inspect, mutate, or block LLM and tool calls. Hook contexts expose CrewAI-compatible camelCase and snake_case fields where useful.
import { afterLlmCall, beforeToolCall } from "@crewai-ts/core"; afterLlmCall((context) => { if (typeof context.response === "string") { return context.response.replace("SECRET", "[redacted]"); } return null; }); beforeToolCall((context) => { if (context.tool_name === "delete_file") { return false; } return null; });
Agents, crews, and tasks expose a fingerprint through SecurityConfig for
identity, auditing, and deterministic seed-based identifiers.
import { Agent, Fingerprint, SecurityConfig } from "@crewai-ts/core"; const securityConfig = new SecurityConfig({ fingerprint: Fingerprint.generate("research-agent", { version: "1.0" }), }); const agent = new Agent({ role: "Researcher", goal: "Find facts", backstory: "Careful analyst", securityConfig, }); console.log(agent.fingerprint.uuid_str);
CheckpointConfig, JsonProvider, and SqliteProvider provide CrewAI-compatible
checkpoint configuration and checkpoint storage. Agents, crews, and flows accept
a checkpoint option.
import { CheckpointConfig, JsonProvider, SqliteProvider } from "@crewai-ts/core"; const checkpoint = new CheckpointConfig({ location: ".checkpoints", onEvents: ["task_completed"], provider: new JsonProvider(), }); const sqliteCheckpoint = new CheckpointConfig({ location: ".checkpoints.db", provider: new SqliteProvider(), });
Tools can be attached to agents or tasks. Task tools take precedence during that task, matching CrewAI's task-level override behavior.
import { Agent, StructuredTool, Task } from "@crewai-ts/core"; const search = new StructuredTool({ name: "search", description: "Search for a topic", argsSchema: { query: { type: "string", required: true }, }, maxUsageCount: 3, func: ({ query }) => `found ${String(query)}`, }); const researcher = new Agent({ role: "Researcher", goal: "Find facts", backstory: "Careful analyst", tools: [search], maxRpm: 30, stepCallback: (step) => { console.log(step.type, step.output); }, llm: () => ({ toolName: "search", arguments: { query: "CrewAI" } }), }); const task = new Task({ description: "Research {topic}", expectedOutput: "A concise brief", agent: researcher, guardrails: [ (output) => [output.raw.length > 0, output.raw], ], });
When an LLM returns a tool call, the agent executes the tool, appends the tool
result to the message list, and calls the LLM again until it returns a final
answer or reaches maxIter. Tools marked resultAsAnswer return their tool
output directly. Set functionCallingLlm on an Agent or Crew when tool-call
selection should use a separate model from the main answer-generating LLM.
Tools cache successful outputs by normalized arguments. Use cacheFunction to
skip selected writes, or pass a shared InMemoryToolCache to reuse cached
results across tool instances.
Agents accept either a function LLM, an object provider with call(), or a
registered model name. Function LLMs receive the message list and call options;
object providers can expose getUsageMetrics() or CrewAI-style
getTokenUsageSummary() for exact token accounting. When they do not, the
runtime records an estimated usage count.
Native providers are installed and registered from their own packages. For a
Gemini-only project, install only @crewai-ts/core and @crewai-ts/gemini:
import { Agent } from "@crewai-ts/core"; import { GeminiCompletion, registerGeminiProvider } from "@crewai-ts/gemini"; registerGeminiProvider(); const researcher = new Agent({ role: "Researcher", goal: "Find facts", backstory: "Careful analyst", llm: new GeminiCompletion({ model: "gemini-2.5-flash" }), });
import { Agent, registerLLMProvider } from "@crewai-ts/core"; registerLLMProvider("local/research", { call: async (messages, { tools } = {}) => { return `tools available: ${tools?.map((tool) => tool.name).join(", ") ?? "none"}`; }, getUsageMetrics: () => ({ totalTokens: 12, promptTokens: 8, cachedPromptTokens: 0, completionTokens: 4, reasoningTokens: 0, cacheCreationTokens: 0, successfulRequests: 1, }), }); const researcher = new Agent({ role: "Researcher", goal: "Find facts", backstory: "Careful analyst", llm: "local/research", }); await researcher.kickoff("Summarize the notes", { inputFiles: { notes: "docs/notes.txt", }, }); await researcher.kickoff([ { role: "user", content: "Summarize the uploaded notes", files: { notes: "docs/notes.txt", }, }, ]);
Agents can create a reasoning plan before executing a task. planning: true
uses a bounded low-effort default config, while PlanningConfig exposes the
custom prompt and limit knobs.
import { Agent, PlanningConfig } from "@crewai-ts/core"; const researcher = new Agent({ role: "Researcher", goal: "Find facts", backstory: "Careful analyst", llm: "local/research", planningConfig: new PlanningConfig({ maxSteps: 10, planPrompt: "Plan this task: {description}", }), }); const answer = await researcher.kickoff("Research CrewAI");
Install @crewai-ts/flow to use Flow APIs:
pnpm add @crewai-ts/core @crewai-ts/flow
Flows run decorated methods as a stateful workflow. @start methods begin the
run, @listen methods react to completed methods or router path strings, and
@router methods return the next path label.
import { Flow, and_, listen, router, start } from "@crewai-ts/flow"; class ResearchFlow extends Flow<{ topic?: string; done?: boolean }> { @start() begin(inputs: { topic: string }) { this.state.topic = inputs.topic; return inputs.topic; } @router("begin") route() { return this.state.topic ? "research" : "skip"; } @listen(and_("research", "begin")) finish() { this.state.done = true; return `researched ${this.state.topic}`; } } const result = await new ResearchFlow().kickoff({ inputs: { topic: "CrewAI" }, });
@start("path") is also supported for conditional starts after a method or
router path fires. Flow execution is bounded by maxMethodCalls so cyclic
flows fail clearly instead of running forever.
Inside a flow, use this.kickoffCrew(crew) to run a crew with the flow's
inputFiles / input_files automatically forwarded.
Flows can request user input through this.ask(). Set an inputProvider on
the flow instance or flowConfig.inputProvider globally. Providers may return
a string, null, or { text, metadata }; responses are available through
flow.inputHistory.
const flow = new ResearchFlow({ inputProvider: { requestInput: async (_message, _flow, metadata) => ({ text: "CrewAI", metadata: { source: metadata?.channel }, }), }, }); const topic = await flow.ask("Topic?", { metadata: { channel: "research" }, timeout: 30, });
Flow methods can also be wrapped with @humanFeedback. The method output is
sent to a feedback provider, the result is stored on
flow.lastHumanFeedback / flow.humanFeedbackHistory, and emit values make
the method act as a router.
class ReviewFlow extends Flow { @start() @humanFeedback({ message: "Review this draft", emit: ["approved", "rejected"], provider: { requestFeedback: async () => "approved", }, }) draft() { return "Draft content"; } @listen("approved") publish() { return this.lastHumanFeedback?.output; } }
Providers that hand off review to an external system can throw
HumanFeedbackPending. kickoff() returns that object, emits
method_execution_paused and flow_paused, and does not treat the pause as a
Flow failure. The same Flow instance can continue with resume(feedback) or
resumeAsync(feedback), which records lastHumanFeedback and resumes any
listeners waiting on the paused method or emitted outcome.
provider: { requestFeedback: (context) => { throw new HumanFeedbackPending({ context, callbackInfo: { ticketId: "review-123" }, }); }, }
To resume after process restart, provide a JsonFlowPersistence in the Flow
constructor. Pending feedback is written with the current state and can be
restored with Flow.fromPending(flowId, persistence).
const persistence = new JsonFlowPersistence(".flows"); const pending = await flow.kickoff(); if (pending instanceof HumanFeedbackPending && pending.context.flowId) { const restored = await ReviewFlow.fromPending(pending.context.flowId, persistence); await restored.resume("approved"); }
The same persistence object stores ordinary Flow state after each completed
method. Use Flow.fromState(flowId, persistence) to restore the latest state
snapshot for a Flow id.
After a run, flow.methodOutputs, flow.completedMethods,
flow.methodExecutionCounts, and flow.executionTrace expose the last
execution's method-level runtime state.
Use getFlowStructure(flowOrClass) to inspect the static Flow graph for
visualization or tooling.
Use flow.toExecutionData() and flow.reload(data) to export and restore the
last run's state, completed methods, method outputs, and execution trace.
Flows emit flow_started, flow_input_requested, flow_input_received,
human_feedback_requested, human_feedback_received,
method_execution_started, method_execution_finished,
method_execution_failed, method_execution_paused, flow_finished,
flow_failed, and flow_paused events on crewaiEventBus.
Tasks can persist their final output to a file. Paths support the same input interpolation as task descriptions, and directories are created by default.
const report = new Task({ description: "Research {topic}", expectedOutput: "A concise brief", agent: researcher, outputFile: "reports/{topic}.md", });
Tasks can attach named text input files. The runtime loads their content into
the task prompt so function LLMs and text-only providers can consume the same
named file surface. When input files are present, the runtime also exposes a
read_file tool that accepts { file_name: "notes" }.
const task = new Task({ description: "Summarize the provided notes", expectedOutput: "A concise summary", agent: researcher, inputFiles: { notes: "docs/notes.txt", inline: { filename: "brief.md", contentType: "text/markdown", content: "# Brief\nSummarize this.", }, }, }); const result = await new Crew({ agents: [researcher], tasks: [task] }).kickoff({ inputFiles: { sharedNotes: "docs/shared-notes.txt", }, });
Structured file objects passed through kickoff({ inputs }) are extracted into
the same input-file surface and removed from interpolation inputs. Raw string
inputs are left untouched, so normal values such as "docs/notes.txt" are not
treated as files unless passed through inputFiles / input_files.
ConditionalTask evaluates the previous task output before running. When its
condition returns false, the crew records an empty raw task output and continues.
import { ConditionalTask } from "@crewai-ts/core"; const followUp = new ConditionalTask({ description: "Write follow-up details", expectedOutput: "Only needed when the previous task asks for more detail", agent: researcher, condition: (output) => output.raw.includes("needs follow-up"), });
Set humanInput on a task to request feedback after the first output. Empty
feedback accepts the output; non-empty feedback is appended to the next prompt
and the task reruns. Server apps should inject their own provider instead of
using terminal input.
const crew = new Crew({ agents: [reviewer], tasks: [ new Task({ description: "Review the report", expectedOutput: "Approved report", agent: reviewer, humanInput: true, }), ], humanInputProvider: { requestFeedback: async ({ output }) => { return output.raw.includes("approved") ? "" : "Please include approval."; }, }, });
Enable planning to run a planner LLM before task execution. The planner returns
one plan per task, and each task prompt receives its current plan without
mutating the original task description.
const crew = new Crew({ agents: [researcher], tasks: [report], planning: true, planningLlm: "gpt-4o-mini", });
Install @crewai-ts/rag to use Memory, Knowledge, RAG, and PDF text extraction
helpers:
pnpm add @crewai-ts/core @crewai-ts/rag
Enable memory on a crew to append relevant memory context to task prompts and
inject recall/save tools into task execution. Agent-level memory is also
available through new Agent({ memory }) and stores completed agent results.
import { Agent, Crew, Process, Task } from "@crewai-ts/core"; import { Memory } from "@crewai-ts/rag"; const memory = new Memory(); memory.remember("CrewAI supports sequential crews"); const researcher = new Agent({ role: "Researcher", goal: "Use memory", backstory: "Careful analyst", llm: () => ({ toolName: "Search_memory", arguments: { queries: ["sequential crews"] }, }), }); const crew = new Crew({ agents: [researcher], tasks: [ new Task({ description: "Recall CrewAI facts", expectedOutput: "Relevant memories", agent: researcher, }), ], process: Process.sequential, memory, });
Attach Knowledge or knowledgeSources to an agent or crew to inject relevant
source snippets into task prompts as additional information.
import { Agent, Crew, Task } from "@crewai-ts/core"; import { StringKnowledgeSource, TextFileKnowledgeSource } from "@crewai-ts/rag"; const researcher = new Agent({ role: "Researcher", goal: "Use knowledge", backstory: "Careful analyst", llm: (messages) => messages.at(-1)?.content ?? "", }); const crew = new Crew({ agents: [researcher], tasks: [ new Task({ description: "Explain Nest integration", expectedOutput: "Integration guidance", agent: researcher, }), ], knowledgeSources: [ new StringKnowledgeSource("Nest should consume crewai-ts as a normal TypeScript library."), new TextFileKnowledgeSource("knowledge/nest-notes.txt"), ], }); crew.resetMemories("knowledge");
CrewProject mirrors CrewAI's agents.yaml / tasks.yaml workflow. String
references in config are resolved only against this library's decorated methods.
import { Agent, Crew, CrewProject, Process, Task, agent, agentOptionsFromConfig, crew, task, taskOptionsFromConfig, } from "@crewai-ts/core"; class ResearchCrew extends CrewProject { agentsConfig = "config/agents.yaml"; tasksConfig = "config/tasks.yaml"; @agent researcher() { return new Agent(agentOptionsFromConfig(this.agentConfig("researcher"))); } @task researchTask() { return new Task(taskOptionsFromConfig(this.taskConfig("researchTask"))); } @crew crew() { return new Crew({ process: Process.sequential }); } }
This monorepo is built with tsup (ESM + CJS + type
declarations) and tested with Vitest. Every script runs
across the workspace with pnpm -r; see the Monorepo section for
per-package variants and the pnpm-workspace.yaml for
the workspace layout.
pnpm -r build # build ESM + CJS output and declarations for every package pnpm -r check # type-check in no-emit mode for every package pnpm -r test # run the Vitest suite for every package pnpm -r lint # run ESLint across the whole monorepo
pnpm -F @crewai-ts/core build
pnpm -F @crewai-ts/core test
pnpm -F @crewai-ts/nestjs lintMIT © June
This project is an unofficial TypeScript port of CrewAI (Copyright © crewAI, Inc.), which is distributed under the MIT License. It is not affiliated with or endorsed by crewAI, Inc. As required by the MIT License, the original copyright and permission notice are retained in LICENSE.