Kosmesis
Components

AI Steps

A plain status list for an agent's task execution. Purely presentational — no Morphos equivalent.

Installation

npx kosmesis add ai-steps
pnpm dlx kosmesis add ai-steps
yarn dlx kosmesis add ai-steps
bunx kosmesis add ai-steps

Install the following dependencies:

npm install @morphos/icons
pnpm add @morphos/icons
yarn add @morphos/icons
bun add @morphos/icons

Copy and paste the following code into your project.

ai-steps.tsx
import { StatelessComponent } from "@praxisjs/core";import { Component } from "@praxisjs/decorators";import type { Children } from "@praxisjs/shared";import { Icon } from "@morphos/icons";import { cn } from "@/lib/utils";export interface AiStepsProps {  class?: string;  id?: string;  children?: Children;}@Component()export class AiSteps extends StatelessComponent<AiStepsProps> {  render() {    const { class: cls, id, children } = this.props;    return (      <div id={id} data-slot="ai-steps" class={cn("flex flex-col gap-2", cls)}>        {children}      </div>    );  }}export type AiStepStatus = "pending" | "running" | "done" | "error";export interface AiStepProps {  status?: AiStepStatus;  class?: string;  children?: Children;}@Component()export class AiStep extends StatelessComponent<AiStepProps> {  render() {    const { status = "done", class: cls, children } = this.props;    return (      <div data-status={status} class={cn("flex items-center gap-2 text-sm", cls)}>        <span          class={cn(            "flex size-4 shrink-0 items-center justify-center rounded-full text-[10px] leading-none",            "in-data-[status=done]:bg-primary in-data-[status=done]:text-primary-foreground",            "in-data-[status=running]:animate-pulse in-data-[status=running]:bg-primary/30",            "in-data-[status=pending]:bg-muted",            "in-data-[status=error]:bg-destructive in-data-[status=error]:text-destructive-foreground",          )}        >          {status === "done" ? <Icon name="Check" size={10} /> : status === "error" ? <Icon name="X" size={10} /> : ""}        </span>        <span class="in-data-[status=pending]:text-muted-foreground">{children}</span>      </div>    );  }}

Install the following dependencies:

npm install @praxisjs/css @morphos/icons
pnpm add @praxisjs/css @morphos/icons
yarn add @praxisjs/css @morphos/icons
bun add @praxisjs/css @morphos/icons

Copy and paste the following code into your project.

ai-steps.tsx
import { StatelessComponent } from "@praxisjs/core";import { cx, Stylesheet, Styled, tokenVars } from "@praxisjs/css";import { Component } from "@praxisjs/decorators";import type { Children } from "@praxisjs/shared";import { Icon } from "@morphos/icons";import { KosmesisTokens } from "@/lib/kosmesis-theme";const t = tokenVars(KosmesisTokens);class AiStepsStyles extends Stylesheet {  $root = this.css({ display: "flex", flexDirection: "column", gap: "0.5rem" });  $step = this.css({ display: "flex", alignItems: "center", gap: "0.5rem", fontSize: "0.875rem" });  $dot = this.css({    display: "flex",    height: "1rem",    width: "1rem",    flexShrink: 0,    alignItems: "center",    justifyContent: "center",    borderRadius: "9999px",    fontSize: "0.625rem",    lineHeight: 1,    backgroundColor: t.muted,  })    .on('[data-status="done"] &', { backgroundColor: t.primary, color: t.primaryForeground })    .on('[data-status="running"] &', { backgroundColor: `color-mix(in oklab, ${t.primary} 30%, transparent)` })    .on('[data-status="error"] &', { backgroundColor: t.destructive, color: t.destructiveForeground });  $label = this.css({}).on('[data-status="pending"] &', { color: t.mutedForeground });}export interface AiStepsProps {  class?: string;  id?: string;  children?: Children;}@Component()export class AiSteps extends StatelessComponent<AiStepsProps> {  @Styled(AiStepsStyles) $s!: AiStepsStyles;  render() {    const { class: cls, id, children } = this.props;    return (      <div id={id} data-slot="ai-steps" class={cx(this.$s.$root, cls)}>        {children}      </div>    );  }}export type AiStepStatus = "pending" | "running" | "done" | "error";export interface AiStepProps {  status?: AiStepStatus;  class?: string;  children?: Children;}@Component()export class AiStep extends StatelessComponent<AiStepProps> {  @Styled(AiStepsStyles) $s!: AiStepsStyles;  render() {    const { status = "done", class: cls, children } = this.props;    return (      <div data-status={status} class={cx(this.$s.$step, cls)}>        <span class={this.$s.$dot}>          {status === "done" ? <Icon name="Check" size={10} /> : status === "error" ? <Icon name="X" size={10} /> : ""}        </span>        <span class={this.$s.$label}>{children}</span>      </div>    );  }}

Examples

About

Purely presentational — no Morphos equivalent. Distinct from the generic Steps component (numbered, connecting rail, meant for wizards/onboarding): AiSteps is a plain non-collapsible status list meant for showing an agent's live task execution (tool calls, running commands, ...).

Usage

import { AiStep, AiSteps } from "@/components/ui/ai-steps";

<AiSteps>
  <AiStep status="done">Read repository</AiStep>
  <AiStep status="running">Running tests</AiStep>
  <AiStep status="pending">Open pull request</AiStep>
</AiSteps>

Props

AiStep

PropTypeDefault
status"pending" | "running" | "done" | "error""done"
classstring

AiSteps accepts class, id, and children only.

On this page