diff --git a/src/core/simulation.jl b/src/core/simulation.jl
index b77917b4cdd8d83f36e456938e27c5d1edaa94e2..1a6f390390e63f92fbae0cd8bd8272d962ee5559 100644
--- a/src/core/simulation.jl
+++ b/src/core/simulation.jl
@@ -59,6 +59,7 @@ Initialise a model object using a ready-made settings dict. This is
 a helper function for `initialise()`.
 """
 function initmodel(settings::Dict{String, Any})
+    #TODO catch exceptions and print them to the log file
     #TODO remove Agents.jl-related code, reimplement this more cleanly (#72)
     @debug "Initialising model object."
     createdatadir(settings["core.outdir"], settings["core.overwrite"])
@@ -127,6 +128,7 @@ end
 Execute one update of the model.
 """
 function stepsimulation!(model::AgentBasedModel)
+    #TODO catch exceptions and print them to the log file
     with_logger(model.logger) do
         @info "Simulating day $(model.date)."
         #TODO remove Agents.jl-related code, reimplement this more cleanly (#72)
@@ -135,6 +137,8 @@ function stepsimulation!(model::AgentBasedModel)
                 stepagent!(model[a], model)
             catch exc
                 # check if the KeyError comes from the `model[a]` or the function call
+                #FIXME this also silences KeyErrors caused in the species code (e.g.
+                # by accessing dead mates) - will be fixed once I reorganise the code
                 isa(exc, KeyError) && isa(exc.key, Int) ? continue : throw(exc)
             end
         end
diff --git a/src/nature/macros.jl b/src/nature/macros.jl
index 6ca2086d267e72c429db3d6e5af3c66bc2109316..ccf9386f24e055cbd4e32a10df00b25aee6074a1 100644
--- a/src/nature/macros.jl
+++ b/src/nature/macros.jl
@@ -113,7 +113,8 @@ macro phase(name, body)
     #TODO the docstrings give a lot of warnings in the log - can I fix that?
     quote
         Core.@__doc__ function $(esc(name))($(esc(:animal))::Animal, $(esc(:model))::AgentBasedModel)
-            $(esc(:pos)) = $(esc(:animal)).pos
+            #TODO add `self` as a synonym for `animal`
+            $(esc(:pos)) = $(esc(:animal)).pos #XXX does this make sense?
             #$(esc(:date)) = $(esc(:model)).date #XXX does this make sense?
             $(esc(body))
         end
@@ -128,8 +129,7 @@ A utility macro to quickly access an animal's trait value.
 This can only be used nested within [`@phase`](@ref).
 """
 macro trait(traitname)
-    #TODO provide a version that can access another animal's traits
-    #XXX replace with an @v macro? (shorter, and not all variables are "traits")
+    #FIXME actually, we can get rid of this altogether if we add a Python-style `self`
     #XXX This would error if called in the first part of a species definition block
     # (i.e. outside of a @phase block). Although this is specified in the documentation,
     # it is unexpected and liable to be overlooked. Can we add a third clause to
@@ -145,7 +145,7 @@ This can only be used in a context where the `model` object is available
 (e.g. nested within [`@phase`](@ref)).
 """
 macro animal(id)
-    :($(esc(:model))[$(id)])
+    :($(esc(:model))[$(esc(id))])
 end
 
 """
@@ -156,7 +156,7 @@ This can only be used in a context where the `model` object is available
 (e.g. nested within [`@phase`](@ref)).
 """
 macro isalive(id)
-    :(isalive($(id), $(esc(:model))))
+    :(isalive($(esc(id)), $(esc(:model))))
 end
 
 """
diff --git a/src/nature/nature.jl b/src/nature/nature.jl
index 4cd5599ec034e1f7140555702cdcc472f0cd2ccd..2edc9fa9617e7e0c216ed361c6d5d061d5a933ae 100644
--- a/src/nature/nature.jl
+++ b/src/nature/nature.jl
@@ -73,7 +73,7 @@ Update an animal by one day, executing it's currently active phase function.
 """
 function stepagent!(animal::Animal, model::AgentBasedModel)
     animal.age += 1
-    animal.traits[animal.phase](animal,model) #FIXME -> note to self: why?
+    animal.traits[animal.phase](animal,model) #FIXME -> note to self: why, what's wrong?
 end
 
 """
@@ -106,5 +106,3 @@ function updatenature!(model::AgentBasedModel)
     end
     #XXX what else needs to go here?
 end
-
-#TODO test migration
diff --git a/src/nature/populations.jl b/src/nature/populations.jl
index d7680ecf6f71c15cfece0be16bf03c8c09437ebf..2288ecde68081e7b59a248b60d1bdccee09ee907 100644
--- a/src/nature/populations.jl
+++ b/src/nature/populations.jl
@@ -39,7 +39,7 @@ This can be used to create the `initialise!` variable in a species definition bl
 function initpopulation(habitatdescriptor::Function; phase::Union{String,Nothing}=nothing,
                         popsize::Int64=-1, popdensity::Int64=-1, pairs::Bool=false,
                         asexual::Bool=false, initfunction::Function=(a,m)->nothing)
-    #TODO add a constructor function for the individual?
+    #TODO add a constructor function/macro for the individual
     function(species::Dict{String,Any}, model::AgentBasedModel)
         n = 0
         lastn = 0
@@ -107,7 +107,7 @@ function reproduce!(animal::Animal, model::AgentBasedModel, mate::Int64, n::Int6
     for i in 1:n
         sex = (animal.sex == hermaphrodite) ? hermaphrodite : @rand([male, female])
         # We need to generate a fresh species dict here
-        species = @eval $(Symbol(animal.traits["name"]))($model)
+        species = @eval $(Symbol(animal.name))($model)
         a = add_agent!(animal.pos, Animal, model, species, (animal.id, mate), sex, 0)
         push!(offspring, a.id)
     end
diff --git a/src/nature/species/skylark.jl b/src/nature/species/skylark.jl
index 50268688c19e2deee6d777b459d6cd514f3d697f..f79c9fea027acd6a125d0c42925af8cef7df0309 100644
--- a/src/nature/species/skylark.jl
+++ b/src/nature/species/skylark.jl
@@ -55,7 +55,8 @@ At the moment, this implementation is still in development.
                         # @distanceto(forest) > 5 && # at least 50m from forest edges
                         # @distanceto(builtup) > 5) # and from anthropogenic structures
     
-    @initialise(habitats, popdensity=300, pairs=true, initfunction=initskylark)
+    @initialise(habitats, phase="mating", popdensity=300, pairs=true,
+                initfunction=initskylark)
     
     """
     As an egg, simply check for mortality and hatching.
@@ -101,7 +102,7 @@ At the moment, this implementation is still in development.
     @phase nonbreeding begin
         # flocking behaviour - follow a random neighbour or move randomly
         #TODO add feeding and mortality, respect habitat when moving
-        neighbours = map(a->a.id, @neighbours(10))
+        neighbours = map(a->a.id, @neighbours(10)) #FIXME
         #isempty(neighbours) ? @randomwalk(5) : @follow(@rand(neighbours), 2)
         if isempty(neighbours)
             @randomwalk(5)
@@ -133,17 +134,17 @@ At the moment, this implementation is still in development.
                 return
             end
             m, d = monthday(model.date)
-            nest = ((m == @trait(nestingbegin)[1] && d > @trait(nestingbegin)[2]
+            nest = ((m == @trait(nestingbegin)[1] && d >= @trait(nestingbegin)[2]
                      && @chance(0.05)) || (m > @trait(nestingbegin)[1]))
             nest && @setphase(nestbuilding)
             return
         end
         # look for a mate among the neighbouring birds, or move randomly
         for n in @neighbours(50)
-            if n.sex != @trait(sex) && n.mate == -1
+            if n.sex != @trait(sex) && n.phase == "mating" && n.mate == -1
                 @trait(mate) = n.id
                 n.mate = @trait(id)
-                @debug "$(animalid(@trait(id))) and $(animalid(n.id)) have mated."
+                @debug "$(animalid(animal)) and $(animalid(n)) have mated."
                 return
             end
         end
@@ -154,26 +155,35 @@ At the moment, this implementation is still in development.
     Females select a location and build a nest. Males do nothing. (Sound familiar?)
     """
     @phase nestbuilding begin
+        if !@isalive(@trait(mate))
+            @setphase(nonbreeding)
+            return
+        end
         if @trait(sex) == female
             if isempty(@trait(nest))
                 # try to find a nest in the neighbourhood, or move on
-                nest = @randompixel(10, @trait(habitats))
-                if isnothing(nest)
-                    nest = ()
+                nestlocation = @randompixel(10, @trait(habitats))
+                if isnothing(nestlocation)
                     @randomwalk(20)
                 else
                     # if we've found a location, start the clock on the building time
                     # (building time doubles for the first nest of the year)
+                    @trait(nest) = nestlocation
                     @trait(nestcompletion) = @rand(nestbuildingtime)
                     month(model.date) == 4 && (@trait(nestcompletion) *= 2)
+                    @debug "$(animalid(animal)) is building a nest."
                 end
             else
                 # wait while nest is being built, then lay eggs and go to next phase
                 if @trait(nestcompletion) > 0
                     @trait(nestcompletion) -= 1
                 else
+                    #XXX more accurately, a female lays one egg per day, not all at once
                     @trait(clutch) = @reproduce(@trait(mate), @rand(eggsperclutch))
                     @animal(@trait(mate)).clutch = @trait(clutch)
+                    for c in @trait(clutch) #FIXME find a cleaner solution for this
+                        initskylark(@animal(c), model)
+                    end
                     @setphase(breeding)
                 end
             end
@@ -224,7 +234,7 @@ function initskylark(animal::Animal, model::AgentBasedModel)
         @migrate(returndate)
     end
     # set individual life-history parameters that are defined as ranges for the species
-    @trait(nestlingtime) = @rand(@trait(nestlingtime))
+    @trait(nestlingtime) = @rand(@trait(nestlingtime)) #FIXME no effect?
     @trait(fledglingtime) = @rand(@trait(fledglingtime))
     #TODO other stuff?
 end
diff --git a/src/world/landscape.jl b/src/world/landscape.jl
index b324298db50e8da1f8b917e4f20cd70edf8f5ab0..220e51f8979b431d5786943845fe054759dd5040 100644
--- a/src/world/landscape.jl
+++ b/src/world/landscape.jl
@@ -184,8 +184,8 @@ habitatdescriptor (create this using [`@habitat`](@ref)).
 """
 function randompixel(pos::Tuple{Int64,Int64}, model::AgentBasedModel, range::Int64=1,
                      habitatdescriptor::Function=(pos,model)->nothing)
-    for x in @shuffle!((pos[1]-range):(pos[1]+range))
-        for y in @shuffle!((pos[2]-range):(pos[2]+range))
+    for x in @shuffle!(collect((pos[1]-range):(pos[1]+range)))
+        for y in @shuffle!(collect((pos[2]-range):(pos[2]+range)))
             !inbounds((x,y), model) && continue
             habitatdescriptor((x,y), model) && return (x,y)
         end