--- title: Legacy Software Automation | Lightcone description: Northstar operates enterprise software through the GUI — no API required. --- Salesforce Classic, SAP, Oracle Forms, internal admin panels, government portals — critical business software that runs entirely through a GUI with no usable API. Northstar operates these systems the same way your team does: by looking at the screen and clicking through the interface. ## Operate a legacy web application legacy\_crm.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 Contacts > New Contact. " "Fill in: First Name 'Jane', Last Name 'Smith', " "Email 'jane.smith@acme.com', Company 'Acme Corp'. " "Click Save. " "Verify the contact was created successfully." ), kind="desktop", max_steps=30, ): print(event) ``` legacy\_crm.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 Contacts > New Contact. " + "Fill in: First Name 'Jane', Last Name 'Smith', " + "Email 'jane.smith@acme.com', Company 'Acme Corp'. " + "Click Save. Verify the contact was created successfully.", kind: "desktop", max_steps: 30, }); for await (const event of stream) { console.log(event); } ``` Northstar finds the fields, handles dropdowns, navigates multi-step forms, and adapts when the layout changes. No selectors to maintain. ## Operate a desktop application Northstar isn’t limited to web apps. On a full desktop, it can operate any native application: ``` with client.computer.create(kind="desktop", persistent=True) as computer: # Install the software if needed client.computers.exec.sync(computer.id, command="apt-get install -y libreoffice") for event in client.agent.tasks.start_stream( instruction=( "Open LibreOffice Calc. " "Create a new spreadsheet with columns: Date, Description, Amount, Category. " "Enter 5 sample expense entries. " "Add a SUM formula at the bottom of the Amount column. " "Save the file as /tmp/expenses.xlsx." ), kind="desktop", environment_id=computer.id, # reuse the environment with LibreOffice installed max_steps=40, ): print(event) ``` ``` // Set up the environment const computer = await client.computers.create({ kind: "desktop", persistent: true, }); await client.computers.exec.sync(computer.id!, { command: "apt-get install -y libreoffice", }); await client.computers.delete(computer.id!); // Run the task const stream = await client.agent.tasks.startStream({ instruction: "Open LibreOffice Calc. " + "Create a new spreadsheet with columns: Date, Description, Amount, Category. " + "Enter 5 sample expense entries. " + "Add a SUM formula at the bottom of the Amount column. " + "Save the file as /tmp/expenses.xlsx.", kind: "desktop", environment_id: computer.id!, max_steps: 40, }); for await (const event of stream) { console.log(event); } ``` ## Process a queue of records Automate repetitive data entry across a legacy system: ``` records = [ {"name": "Jane Smith", "email": "jane@acme.com", "role": "Manager"}, {"name": "Bob Chen", "email": "bob@acme.com", "role": "Engineer"}, {"name": "Sara Lee", "email": "sara@acme.com", "role": "Director"}, ] for record in records: print(f"Creating user: {record['name']}") for event in client.agent.tasks.start_stream( instruction=( f"Go to https://admin.example.com/users/new. " f"Fill in Name: '{record['name']}', Email: '{record['email']}', Role: '{record['role']}'. " f"Click Create User. Verify the success message appears." ), kind="desktop", max_steps=15, ): print(f" {event}") ``` ``` const records = [ { name: "Jane Smith", email: "jane@acme.com", role: "Manager" }, { name: "Bob Chen", email: "bob@acme.com", role: "Engineer" }, { name: "Sara Lee", email: "sara@acme.com", role: "Director" }, ]; for (const record of records) { console.log(`Creating user: ${record.name}`); const stream = await client.agent.tasks.startStream({ instruction: `Go to https://admin.example.com/users/new. ` + `Fill in Name: '${record.name}', Email: '${record.email}', Role: '${record.role}'. ` + `Click Create User. Verify the success message appears.`, kind: "desktop", max_steps: 15, }); for await (const event of stream) { console.log(` ${JSON.stringify(event)}`); } } ``` ## Why Northstar for legacy software | | RPA (UiPath, Automation Anywhere) | Northstar | | ---------------- | --------------------------------------- | -------------------------------------- | | **Setup** | Weeks of scripting with visual builders | One natural language instruction | | **Maintenance** | Breaks on every UI change | Adapts — reads the screen like a human | | **Desktop apps** | Requires recording + selectors | Works on any GUI out of the box | | **Cost** | $500K+ enterprise licenses | Pay per task | Northstar is especially effective for forms with dynamic fields, conditional logic, dropdowns, and date pickers — the exact patterns that make traditional RPA scripts fragile. ## See also - [**Cross-application workflows**](/use-cases/cross-app-workflows/index.md) — move data between multiple legacy systems - [**Software testing**](/use-cases/software-testing/index.md) — test legacy applications without selectors - [**Tasks**](/guides/tasks/index.md) — configuration, streaming, and writing effective instructions - [**Lightcone OS**](/guides/lightcone-os/index.md) — install enterprise software in the environment