Skip to content
NorthstarPlatformPricingLogin

Cross-Application Workflows

Northstar moves data between applications that don't have APIs — CRM to spreadsheet, email to database, portal to portal.

Most enterprise work involves copying data between applications that don’t 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) don’t have APIs, or the APIs don’t expose what you need
  • Multiple applications — the workflow spans 2-5 different systems, each with its own interface
  • Human judgment — the operator needs to read one screen and decide what to enter in another

Northstar handles all three. It operates the desktop like a human — switching between apps, reading data from one, entering it in another — but without getting tired, making typos, or taking lunch breaks.

  • 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