What Puppet is & the model
Declarative, agent/master, model-driven.
Puppet is a configuration-management system built around a declarative, model-driven language: you describe the desired state of a machine — these packages installed, this file present with these contents, this service running — and Puppet figures out how to make it so and keeps it that way. You do not write the steps; you write the model, and Puppet’s engine reconciles reality to it. This declarative purity is Puppet’s defining trait and its main difference from more procedural tools.
The classic architecture is agent/master pull: a Puppet agent on each node checks in with a Puppet master (server) on a schedule, sends its facts, receives a compiled catalog of desired state, applies it, and reports back. Like Chef, it is agent-based and self-correcting; unlike Chef’s Ruby recipes, Puppet’s language is a purpose-built DSL that is declarative first, which pushes you toward describing state rather than scripting it.
Declarative, not ordered by default
A crucial mental shift: Puppet does not run resources in the order you write them unless you tell it to. It builds a graph from explicit dependencies (require, before, notify, subscribe) and applies resources in dependency order, not source order. This trips people coming from scripts — you must declare relationships rather than assuming top-to-bottom execution. Once internalized, it is what lets Puppet reason about and optimize convergence.