Skip to content
Try out in chatDeveloper dashboardLogin

Cross-Application Workflows

Northstar moves data between applications that have no APIs, from CRM to spreadsheet, email to database, portal to portal.

Most enterprise work involves copying data between applications that do not talk to each other: pulling a record from the CRM, entering it into a spreadsheet, filing it in an internal tool, sending a confirmation email. These workflows run on human operators clicking between windows all day.

Northstar operates the desktop the same way those operators do, but 24/7, across thousands of instances simultaneously.

Move data between a web app and a spreadsheet

Section titled “Move data between a web app and a spreadsheet”
crm_to_spreadsheet.py
from tzafon import Lightcone
client = Lightcone()
for event in client.agent.tasks.start_stream(
instruction=(
"Open Firefox and go to https://crm.example.com. Log in with 'ops@example.com' / 'ops123'. "
"Navigate to the Contacts page. Find the contact 'Acme Corp'. "
"Note their email address, phone number, and account status. "
"Then open LibreOffice Calc. "
"Enter the headers 'Company', 'Email', 'Phone', 'Status' in row 1. "
"Enter the Acme Corp data in row 2. "
"Save the file as /tmp/acme-export.csv."
),
kind="desktop",
max_steps=40,
):
print(event)
crm_to_spreadsheet.ts
import Lightcone from "@tzafon/lightcone";
const client = new Lightcone();
const stream = await client.agent.tasks.startStream({
instruction:
"Open Firefox and go to https://crm.example.com. Log in with 'ops@example.com' / 'ops123'. " +
"Navigate to the Contacts page. Find the contact 'Acme Corp'. " +
"Note their email address, phone number, and account status. " +
"Then open LibreOffice Calc. " +
"Enter the headers 'Company', 'Email', 'Phone', 'Status' in row 1. " +
"Enter the Acme Corp data in row 2. " +
"Save the file as /tmp/acme-export.csv.",
kind: "desktop",
max_steps: 40,
});
for await (const event of stream) {
console.log(event);
}

Northstar opens the CRM in a browser, finds the data, switches to a spreadsheet application, enters it, and saves the file. Two applications, one instruction.

# Process each record: look it up in system A, enter it in system B
records = [
{"name": "Acme Corp", "action": "renew"},
{"name": "Globex Inc", "action": "upgrade"},
{"name": "Initech LLC", "action": "cancel"},
]
for record in records:
print(f"Processing {record['name']}...")
for event in client.agent.tasks.start_stream(
instruction=(
f"Open Firefox and go to https://portal.example.com. "
f"Search for '{record['name']}'. "
f"Click on their account. "
f"Click the '{record['action'].title()}' button. "
f"Confirm the action. "
f"Report whether it succeeded."
),
kind="desktop",
max_steps=20,
):
print(f" {event}")
const records = [
{ name: "Acme Corp", action: "renew" },
{ name: "Globex Inc", action: "upgrade" },
{ name: "Initech LLC", action: "cancel" },
];
for (const record of records) {
console.log(`Processing ${record.name}...`);
const stream = await client.agent.tasks.startStream({
instruction:
`Open Firefox and go to https://portal.example.com. ` +
`Search for '${record.name}'. Click on their account. ` +
`Click the '${record.action}' button. Confirm the action. ` +
`Report whether it succeeded.`,
kind: "desktop",
max_steps: 20,
});
for await (const event of stream) {
console.log(` ${JSON.stringify(event)}`);
}
}

Use persistent state for multi-session workflows

Section titled “Use persistent state for multi-session workflows”

Install software, configure the environment once, and reuse it across runs:

# First run: set up the environment
with client.computer.create(kind="desktop", persistent=True) as computer:
# Install tools Northstar will need
client.computers.exec.sync(computer.id, command="apt-get install -y libreoffice")
saved_id = computer.id
print(f"Environment ready: {saved_id}")
# Subsequent runs: reuse the environment
for event in client.agent.tasks.start_stream(
instruction="Open LibreOffice Calc, load /tmp/data.csv, and add a 'Total' column that sums columns B through D",
kind="desktop",
environment_id=saved_id,
):
print(event)
// First run: set up
const computer = await client.computers.create({
kind: "desktop",
persistent: true,
});
await client.computers.exec.sync(computer.id!, {
command: "apt-get install -y libreoffice",
});
const savedId = computer.id!;
await client.computers.delete(savedId);
// Subsequent runs: reuse
const stream = await client.agent.tasks.startStream({
instruction: "Open LibreOffice Calc, load /tmp/data.csv, and add a 'Total' column that sums columns B through D",
kind: "desktop",
environment_id: savedId,
});
for await (const event of stream) {
console.log(event);
}

These workflows are hard to automate traditionally because:

  • No APIs. Many enterprise apps, especially legacy ones, have no APIs, or the APIs do not expose what you need
  • Multiple applications. The workflow spans two to five systems, each with its own interface
  • Human judgment. The operator reads one screen and decides what to enter in another

Northstar handles all three. It operates the desktop like a human, switching between apps, reading data from one and entering it in another, and it runs unattended.

  • Tasks: run workflows with natural language instructions
  • Shell commands: combine GUI automation with CLI tools
  • Lightcone OS: install the software your workflows need
  • Computers: persistent state for long-running workflows